Created
April 1, 2020 13:05
-
-
Save buschtoens/916236539bcbbdb3d13c5323385809db to your computer and use it in GitHub Desktop.
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
/** | |
* Big thanks to @dfreeman (Dan Freeman) for this! | |
* | |
* @see https://discordapp.com/channels/480462759797063690/484421406659182603/694852926572593253 | |
*/ | |
/** | |
* Retrieves the type of a type guard function. | |
* Like `ReturnType<T>`, but for type guard functions. | |
* | |
* @example | |
* ```ts | |
* type Foo = TypeOfGuard<(subject: unknown) => is { foo: string }>; | |
* // => { foo: string } | |
* ``` | |
*/ | |
export type TypeOfGuard<T extends (subject: unknown) => unknown> = T extends ( | |
subject: unknown | |
) => subject is infer Type | |
? Type | |
: never; | |
/** | |
* Create a tuple of type guard functions from the specified types. | |
* | |
* @example | |
* ```ts | |
* type StringNumber = Predicates<[string, number]>; | |
* // => [ | |
* // (v: unknown) => v is string, | |
* // (v: unknown) => v is number | |
* // ] | |
* ``` | |
*/ | |
type Predicates<T extends unknown[]> = { | |
[K in keyof T]: (subject: unknown) => subject is T[K]; | |
} & | |
unknown[]; | |
/** | |
* Converts a union type (`A | B`) to an intersection type (`A & B`). | |
*/ | |
type UnionToIntersection<T> = (T extends T | |
? (p: T) => void | |
: never) extends (p: infer U) => void | |
? U | |
: never; | |
/** | |
* Gets all values of a tuple as a union type (`A | B`). | |
* | |
* @example | |
* ```ts | |
* type StringOrNumber = UnionOf<[string, number]>; // => string | number | |
* ``` | |
*/ | |
type UnionOf<T extends unknown[]> = T[keyof T & number]; | |
/** | |
* Gets all values of a tuple as an intersection type (`A & B`). | |
* | |
* @example | |
* ``` | |
* type FooAndBar = IntersectionOf<[{ foo: string }, { bar: string }]>; | |
* ``` | |
*/ | |
type IntersectionOf<T extends unknown[]> = UnionToIntersection<UnionOf<T>>; | |
/** | |
* Combines a list of type guard functions into a union type guard. | |
* | |
* @example | |
* ```ts | |
* type Foo = { foo: boolean; baz: number }; | |
* type Bar = { bar: symbol; baz: string }; | |
* | |
* declare function isFoo(v: unknown): v is Foo; | |
* declare function isBar(v: unknown): v is Bar; | |
* | |
* const isFooOrBar = isSome(isFoo, isBar); | |
* // => (subject: unknown) => subject is Foo | Bar | |
* ``` | |
*/ | |
export const isSome = <Types extends unknown[]>( | |
...predicates: Predicates<Types> | |
) => (subject: unknown): subject is UnionOf<Types> => | |
predicates.some(is => is(subject)); | |
/** | |
* Combines a list of type guard functions into an intersection type guard. | |
* | |
* @example | |
* ```ts | |
* type Foo = { foo: boolean; baz: number }; | |
* type Bar = { bar: symbol; baz: string }; | |
* | |
* declare function isFoo(v: unknown): v is Foo; | |
* declare function isBar(v: unknown): v is Bar; | |
* | |
* const isFooAndBar = isEvery(isFoo, isBar); | |
* // => (subject: unknown) => subject is Foo & Bar | |
* ``` | |
*/ | |
export const isEvery = <Types extends unknown[]>( | |
...predicates: Predicates<Types> | |
) => (subject: unknown): subject is IntersectionOf<Types> => | |
predicates.every(is => is(subject)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment