Created
January 3, 2019 11:16
-
-
Save gtkatakura-bysoft/d45e7407136a25da63599f3436ffc7af to your computer and use it in GitHub Desktop.
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
```ts | |
type Tail<F extends Function, S extends Number> = | |
S extends 0 ? (F extends (...args: infer TArgs) => any ? TArgs : never) : | |
S extends 1 ? (F extends (a: any, ...args: infer TArgs) => any ? TArgs : never) : | |
S extends 2 ? (F extends (a: any, b: any, ...args: infer TArgs) => any ? TArgs : never) : | |
S extends 3 ? (F extends (a: any, b: any, c: any, ...args: infer TArgs) => any ? TArgs : never) : | |
S extends 4 ? (F extends (a: any, b: any, c: any, d: any, ...args: infer TArgs) => any ? TArgs : never) : | |
S extends 5 ? (F extends (a: any, b: any, c: any, d: any, e: any, ...args: infer TArgs) => any ? TArgs : never) : | |
S extends 6 ? (F extends (a: any, b: any, c: any, d: any, e: any, f: any, ...args: infer TArgs) => any ? TArgs : never) : | |
never | |
type TailArray<A extends any[], S extends Number> = | |
Tail<(...args: A) => any, S> | |
type Args<T extends Function> = | |
T extends (...args: infer TArgs) => any ? TArgs | |
: never | |
type PartialArgs<T extends Function> = | |
T extends (...args: infer TArgs) => any ? Partial<TArgs> | |
: never | |
type Curried<T extends (...args: any) => any, TReturn = ReturnType<T>> = | |
< | |
TArgs extends PartialArgs<T>, | |
TRest extends TailArray<Args<T>, TArgs['length']> | |
>(...args: TArgs) => | |
TRest extends [] | |
? TReturn | |
: Curried<(...args: TRest) => TReturn> | |
type Curry = <TFunc extends (...args: any) => any>(func: TFunc) => Curried<TFunc> | |
declare const curry: Curry | |
const curried = curry((a: 1 | undefined, b: number | number[], c: string) => 1) | |
// works :D | |
const a = curried(1)([2])('x') | |
const b = curried(1)(2, 'x') | |
const c = curried(1, 2)('x') | |
const d = curried(1, 2, 'x') | |
// the only problem is that `undefined` is accepted | |
// Partial<[1, 2]> => [1 | undefined, 2 | undefined] | |
curried(undefined)(2)(undefined) | |
``` | |
```ts | |
type Init<T extends any[], TTail extends any[] = TailArray<T>> = CastArray<{ | |
[K in keyof TTail]: T[keyof T & K]; | |
}> | |
type PotentialArgs<T extends any[], TResult extends any[] = T> = { | |
"continue": PotentialArgs<Init<T>, TResult | Init<T>>; | |
"end": TResult; | |
}[T extends [] ? "end" : "continue"] | |
type Args<T extends Function> = | |
T extends (...args: infer TArgs) => any ? TArgs | |
: never | |
type TailArgs<F extends Function> = | |
F extends (head: any, ...tail: infer TTail) => any ? TTail : | |
never | |
type TailArray<A extends any[]> = TailArgs<(...args: A) => any> | |
type CastArray<T> = T extends any[] ? T : [] | |
type DropFromArraySize<TSource extends any[], TSize extends any[]> = CastArray<{ | |
"continue": DropFromArraySize<TailArray<TSource>, TailArray<TSize>>, | |
"end": TSource, | |
}[TSize extends [] ? "end" : "continue"]> | |
type PartialArgs<T extends Function> = | |
T extends (...args: infer TArgs) => any ? Partial<TArgs> | |
: never | |
type Curried<T extends (...args: any) => any> = | |
< | |
TInitArgs extends PotentialArgs<Args<T>>, | |
TTailArgs extends DropFromArraySize<Args<T>, TInitArgs> | |
>(...args: TInitArgs) => | |
TTailArgs extends [] | |
? ReturnType<T> | |
: Curried<(...args: TTailArgs) => ReturnType<T>> | |
type Curry = <TFunc extends (...args: any) => any>(func: TFunc) => Curried<TFunc> | |
declare const curry: Curry | |
const curried = curry((a: 1 | undefined, b: number | number[], c: string) => 1) | |
// works :D | |
const a = curried(1)([2])('x') | |
const b = curried(1)(2, 'x') | |
const c = curried(1, 2)('x') | |
const d = curried(1, 2, 'x') | |
const e = curried(undefined)(2)('2') | |
curried(undefined)(2)(undefined) // notify error | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment