Last active
August 7, 2020 12:33
-
-
Save karol-majewski/285a1db731103d01d61444ae3cfa699f to your computer and use it in GitHub Desktop.
Type-safe refinements (type guards) in TypeScript (moved to https://github.com/karol-majewski/refinements)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Refinement { | |
class Hit<T> { | |
constructor(readonly value: T) {} | |
} | |
class Miss {} | |
type Result<T> = Hit<T> | Miss; | |
export function hit<T> (value: T) { | |
return new Hit(value); | |
} | |
export const miss = new Miss(); | |
export function create<T, U extends T>(refine: (candidate: T) => Result<U>): (candidate: T) => candidate is U { | |
return (candidate): candidate is U => refine(candidate) instanceof Hit; | |
} | |
} |
With regular type guards, it's easy to make a mistake. The body of user-defined type guards is not type-checked.
class Cat {
meow(): void {}
}
class Dog {
bark(): void {}
}
type Pet = Cat | Dog;
const isCat = (pet: Pet): pet is Cat =>
pet instanceof Dog; // Bad!
console.log(
isCat(new Cat()), // false ⛔️
isCat(new Dog()) // true ⛔️
)
The implementation of isCat
is incorrect, but TypeScript doesn't care.
TypeGuard.create
solves that problem.
This approach is used by fp-ts
:
https://gcanti.github.io/fp-ts/modules/Option.ts.html#getrefinement
Type guards use cases: use for filter
and discrimination.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: