Last active
January 11, 2019 00:38
-
-
Save gtkatakura/4f5ec735a4747fb2b9d1f09cf3e5598e to your computer and use it in GitHub Desktop.
// Tuple operations Cons, Head, Tail
type Head<T> = T extends [infer U, ...unknown[]] ? U : never
type Tail<T> = T extends Array<any>
? ((...args: T) => never) extends ((a: any, ...args: infer R) => never)
? R
: never
: never
type Cons<T extends any[], H> = ((h: H, ...t: T) => any) extends ((...x: infer X) => any) ? X : never
// Generic lazy tuple reduction
interface Reduction<Base, In> {
0: Base
1: In
}
type Reduce<T extends Array<any>, R extends Reduction<any, any>> = R[T extends [] ? 0 : 1]
// Tuple reversal
interface ReverseRec<H extends Array<any>, T extends Array<any>>
extends Reduction<H, Reduce<Tail<T>, ReverseRec<Cons<H, Head<T>>, Tail<T>>>> {}
type Reverse<T> = T extends Array<any> ? Reduce<T, ReverseRec<[], T>> : never
// Currying, finally
interface CurryRec<H, T extends Array<any>>
extends Reduction<
H,
Reduce<
Tail<T>,
CurryRec<(arg: Head<T>) => H, Tail<T>>
>
>{}
type Curry<F extends (...args: any[]) => any> = Reverse<Parameters<F>> extends infer R
? R extends any[]
? Reduce<R, CurryRec<ReturnType<F>, R>>
: never
: never
declare function curry<F extends (...args: any[]) => any>(f: F): Curry<F>
declare const f: (a: number, b: string, c: symbol, d: boolean, e: void) => boolean
const curried = curry(f) // (args_0: number) => (args_0: string) => (args_0: symbol) => (args_0: boolean) => (args_0: void) => boolean
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Solution for one thread twitter.