Last active
May 12, 2019 19:44
-
-
Save webstrand/465e8867bbf06ab405506ea90e342505 to your computer and use it in GitHub Desktop.
Utility types for manipulating and traversing lists.
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
| // Find the first item of a list. | |
| export type Head<List extends any[]> = List['length'] extends 0 ? never : List[0]; | |
| // Find the last item of a list. | |
| export type Last<List extends any[]> = number extends List['length'] ? List[1e+309] : _Last<List>; | |
| type _Last< | |
| Tuple extends any[], | |
| _I extends number = Tail<Tuple>['length'] | |
| > = Tuple extends [] ? never : _I extends keyof Tuple ? Tuple[_I] : never; | |
| // Produce a list skipping the first item. | |
| export type Tail<List extends any[]> = ((..._: List) => any) extends ((_: any, ...tail: infer U) => any) ? U : never; | |
| // Produce a list skipping the last item. | |
| export type Init<List extends any[]> = number extends List['length'] ? List : _Init<List>; | |
| type _Init< | |
| Tuple extends any[], | |
| _Tail extends any[] = Tail<Tuple> | |
| > = { | |
| [I in keyof _Tail]: I extends keyof Tuple ? Tuple[I] : never; | |
| }; | |
| // True when the list has a prefix that is a tuple. | |
| export type HasTuplePrefix<List extends any[]> = | |
| // Only lists having a ...T[] component have (number extends List['length']) | |
| number extends List['length'] | |
| // If the list is equivalen to an array of its first element, then the | |
| // list has no leading required elements. | |
| ? List extends List[0][] ? List[0][] extends List ? false : true : true | |
| : true; | |
| // "unshift" the type H onto the beginning of List. | |
| export type Unshift<List extends any[], H> = | |
| ((_: H, ...args: List) => any) extends (...args: infer U) => any ? U : []; | |
| // Extract the required elements from the list. | |
| export type ExtractTuplePrefix<List extends any[]> = | |
| // If the list is finite, avoid doing recursive work and return the list directly. | |
| number extends List['length'] | |
| ? _ExtractTuplePrefix<List> | |
| : List; | |
| // Use only on Lists with non-finite components. | |
| type _ExtractTuplePrefix< | |
| List extends any[], | |
| C extends number[] = [], | |
| _Return = { | |
| 0: C, | |
| 1: _ExtractTuplePrefix<Tail<List>, Unshift<C, 0>> | |
| }[List extends List[0][] ? List[0][] extends List ? 0 : 1 : 1] | |
| > = _Return extends any[] ? _Return : never; | |
| // Find all the suffixes of a list | |
| export type Suffixes< | |
| List extends any[], | |
| _Tail extends any[] = Tail<List> | |
| > = { | |
| 0: List, | |
| 1: List | Suffixes<_Tail>, | |
| 2: List[1e309][] | |
| }[ | |
| _Tail['length'] extends 0 | |
| ? 0 | |
| : number extends List['length'] | |
| ? List extends List[0][] ? List[0][] extends List ? 2 : 1 : 1 | |
| : 1 | |
| ]; | |
| // Find all the prefixes of a tuple, including the tuple itself. | |
| export type Prefixes<List extends any[]> = | |
| number extends List['length'] | |
| ? List extends List[0][] | |
| ? List[0][] extends List | |
| ? List | |
| : _Prefixes<List, Suffixes<_ExtractTuplePrefix<List>>> | List | |
| : _Prefixes<List, Suffixes<_ExtractTuplePrefix<List>>> | List | |
| : _Prefixes<List>; | |
| type _Prefixes< | |
| Tuple extends any[], | |
| _Suffixes = Suffixes<Tuple> | |
| > = { | |
| [I in keyof _Suffixes]: I extends keyof Tuple ? Tuple[I] : never; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment