Created
July 15, 2025 17:34
-
-
Save webstrand/4d8b76ef19655dc0167eeb8f8bb6e841 to your computer and use it in GitHub Desktop.
My favorite way of implementing Union To Tuple in TypeScript
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
| declare const END: unique symbol; | |
| type END = typeof END; | |
| export type UnionToTuple< | |
| T, | |
| I = (() => END) & | |
| ((T extends T ? (x: () => T) => void : never) extends (x: infer U) => void | |
| ? U | |
| : never), | |
| Acc extends readonly unknown[] = [], | |
| > = I extends () => infer K | |
| ? K extends END | |
| ? Acc | |
| : UnionToTuple<T, (() => K) & I, [K, ...Acc]> | |
| : never; | |
| // Relies on the trick that intersecting a component of an intersection with | |
| // the whole intersection causes the component to be reordered not duplicated. | |
| // Relies on the fact that an intersection of function types is considered | |
| // an overloaded function type. | |
| // Relies on the fact that infering the type of an overloaded function returns | |
| // inferences based on the _last_ overload which is the same as the _last_ | |
| // function type in the intersection. | |
| // Using this technique we can rotate the intersection to visit every member | |
| // in order until the unique symbol END is reached. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment