Created
July 12, 2019 16:25
-
-
Save webstrand/d81980a925cddbd8f5ad964ad2a63183 to your computer and use it in GitHub Desktop.
Partial Application for any number of arguments
This file contains 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 readonly unknown[]> = | |
0 extends keyof List ? List[0] : never; | |
// Find the last item of a list. | |
export type Last<List extends readonly unknown[]> = | |
List["length"] extends 0 ? never | |
: List extends [] ? never | |
: number extends List["length"] ? List[1e+309] | |
: List[Tail<List>["length"]]; | |
// Produce a list skipping the first item. | |
export type Tail<List extends readonly unknown[]> = | |
List extends readonly unknown[] ? ((...args: List) => never) extends ((_: any, ...args: infer U) => never) ? U : never : never; | |
// Produce a list skipping the last item. | |
export type Init<List extends readonly unknown[]> = | |
number extends List["length"] ? List | |
: $Init<List>; | |
export type $Init< | |
List extends readonly unknown[], | |
_Tail extends any[] = Tail<List> | |
> = { | |
[I in keyof _Tail]: I extends keyof List ? List[I] : never | |
}; | |
// "unshift" the type H onto the beginning of List. | |
export type Unshift<List extends readonly unknown[], H> = | |
List extends readonly unknown[] ? ((_: H, ...args: List) => any) extends (...args: infer U) => any ? U : never : never; | |
// Shift values from the beginning of List. | |
export type Shift< | |
List extends readonly unknown[], | |
C extends readonly unknown[] = [unknown] | |
> = List extends readonly unknown[] ? C extends readonly unknown[] ? $Shift<List, C> : never : never; | |
export type $Shift< | |
List extends readonly unknown[], | |
C extends readonly unknown[] | |
> = { | |
0: ((...args: List) => any) extends(...args: infer U) => any ?U: [], | |
1: Shift<((...args: List) => any) extends (_: any, ...args: infer U) => any ? U : [], ((...args: C) => any) extends (_: any, ...args: infer U) => any ? U : []>, | |
2: [] | |
}[number extends C["length"] ? 2 : C["length"] extends 0 ? 0 : 1]; | |
// Produce an analogous tuple with the same length as the tuple | |
// prefix of List, but with different value types. | |
type ExtractTupleAnalog<List extends readonly unknown[]> = | |
List extends readonly unknown[] ? { | |
0: List, | |
1: $ExtractTupleAnalog<List> | |
}[number extends List["length"] ? 1 : 0] : never; | |
type $ExtractTupleAnalog< | |
List extends readonly unknown[], | |
C extends readonly any[] = [], | |
> = { | |
0: C, | |
1: $ExtractTupleAnalogStep<List, C>, | |
}[List[0][] extends List ? 0 : 1]; | |
type $ExtractTupleAnalogStep< | |
List extends readonly unknown[], | |
C extends readonly any[], | |
_Tail extends any[] = Tail<List> | |
> = $ExtractTupleAnalog<_Tail, Unshift<C, List[0]>>; | |
// Find all the suffixes of a list | |
export type Suffixes< | |
List extends readonly unknown[], | |
_Tail extends any[] = Tail<List> | |
> = { | |
0: List, | |
1: List | Suffixes<_Tail>, | |
2: List[1e309][] | |
}[ | |
_Tail["length"] extends 0 | |
? 0 | |
: number extends List["length"] | |
? List[0][] extends List ? 2 : 1 | |
: 1 | |
]; | |
// Find all the prefixes of a list | |
export type Prefixes<List extends readonly unknown[]> = | |
number extends List["length"] | |
? List[0][] extends List | |
? List | |
: $Prefixes<ExtractTupleAnalog<List>> | List | |
: (List extends readonly any[] ? $Prefixes<List> : never) | |
type $Prefixes< | |
Tuple extends readonly unknown[], | |
_Suffixes = Suffixes<Tuple> | |
> = { | |
[I in keyof _Suffixes]: I extends keyof Tuple ? Tuple[I] : never; | |
}; | |
// Remove some prefix of parameters from a function without checking types. | |
export type BlindBind< | |
F, | |
B extends unknown[], | |
_Tail extends any[] = ((..._: B) => any) extends ((_: any, ...tail: infer U) => any) ? U : [] | |
> = { | |
0: F, | |
1: BlindBind<F extends (this: infer T, _: any, ...args: infer U) => infer V ? (this: T, ...args: U) => V : F, _Tail> | |
}[B["length"] extends 0 ? 0 : 1]; | |
// Remove some prefix of parameters from a function. | |
export type Bind< | |
F extends (...args: any[]) => any, | |
B extends [] | Prefixes<Parameters<F>> | |
> = B extends any[] ? BlindBind<F, B> : never; | |
type H = Bind<(x: number, y: string, ...z: number[]) => void, [number, string, number]> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment