Skip to content

Instantly share code, notes, and snippets.

@gvergnaud
Last active October 1, 2021 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvergnaud/c84883cbba721fa2ede1c1117b6e5e80 to your computer and use it in GitHub Desktop.
Save gvergnaud/c84883cbba721fa2ede1c1117b6e5e80 to your computer and use it in GitHub Desktop.
// Helpers
type Expect<T extends true> = T
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2)
? true
: false;
type Not<T extends boolean> = T extends true ? false : true;
/**
* Mapping over a union type.
*
* The trick is to use do
* ```ts
* type SomeGenericType<SomeUnion> =
* SomeUnion extends any
* ? {{ use SomeUnion here }}
* : never
* ```
*
* `SomeUnion extends any` is of course always true, but that's not the point.
* The point is to execute the code contained in the first branch for each element of the `SomeUnion` union type.
* This is essentially a map.
*
* /!\ This only works inside of a Generic function!
*/
type Strings = "a" | "b" | "c"
type Gen<T extends string> =
T extends any
? { key: T }
: never
type Gen2<T extends string> =
{ key: T }
type distributed = { key: "a" } | { key: "b" } | { key: "c" }
type nondistributed = { key: "a" | "b" | "c" }
type cases = [
// this two types are NOT equal
Expect<Not<Equal<distributed, nondistributed>>>,
// The distribution works if it's inside a generic type and
// it uses T extends any to distribute all values.
Expect<Equal<Gen<Strings>, distributed>>,
// The distribution DOESN'T works if it's inside a generic type but
// it doesn't uses T extends any.
Expect<Equal<Gen2<Strings>, nondistributed>>,
// This doesn't work when it's inlined (which is a real problem imo, maybe even a bug)
Expect<Equal<
Strings extends infer T
? { key: T }
: never,
nondistributed
>>,
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment