Skip to content

Instantly share code, notes, and snippets.

@webstrand
Created July 12, 2019 16:25
Show Gist options
  • Save webstrand/d81980a925cddbd8f5ad964ad2a63183 to your computer and use it in GitHub Desktop.
Save webstrand/d81980a925cddbd8f5ad964ad2a63183 to your computer and use it in GitHub Desktop.
Partial Application for any number of arguments
// 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