declare function Currying<F>(fn: F): Curried<F>
type Curried<F> = F extends (...args: infer A) => infer R
? A extends [infer First, ...infer Rest]
? (arg: First) => Rest['length'] extends 0 ? R : Curried<(...args: Rest) => R>
: () => R
: never
Solution by wendao-liu #35165
type Curried<T> = T extends (...args: infer A) => infer R ? A extends [] ? () => R : A extends [infer P] ? (p: P) => R : (A extends [infer V, ...infer rest] ? (p: V) => Curried<(...args: rest) => R> : never) : never
declare function Currying<T>(fn: T): Curried<T>
Solution by ouzexi #34196
type Curried<F> = F extends (...args: infer Args) => infer Ret
? Args['length'] extends 0 | 1
? F
: Args extends [any, ...infer RestArgs]
? (...args: Args extends [infer Arg, ...any] ? [Arg] : never) => Curried<(...args: RestArgs) => Ret>
: never
: never
declare function Currying<T extends Function>(
fn: T
): Curried<T>
Solution by Mumujianguang #34000
type Curried<T> = T extends (...args: infer P) => infer R
? P["length"] extends 0 | 1
? T
: P extends [infer F, ...infer L]
? (arg: F) => Curried<(...args: L) => R>
: never
: never;
declare function Currying<T>(
fn: T
): Curried<T>;
Solution by vangie #32231
// your answers
type Curried<Fn> =
Fn extends (...args: infer A) => infer R ?
A extends [infer First, ...infer Rest] ?
(arg: First) => Curried<(...args: Rest) => R> :
R :
never
declare function Currying<Fn>(fn: Fn):
Fn extends (...args: infer A) => infer R ?
A['length'] extends 0 ?
() => R :
Curried<Fn> :
never
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const curried1 = Currying((a: string, b: number, c: boolean) => true)
const curried2 = Currying((a: string, b: number, c: boolean, d: boolean, e: boolean, f: string, g: boolean) => true)
const curried3 = Currying(() => true)
type cases = [
Expect<Equal<
typeof curried1,
(a: string) => (b: number) => (c: boolean) => true
>>,
Expect<Equal<
typeof curried2,
(a: string) => (b: number) => (c: boolean) => (d: boolean) => (e: boolean) => (f: string) => (g: boolean) => true
>>,
Expect<Equal<typeof curried3, () => true>>,
]
Solution by gearonixx #31782
// 你的答案
type FC
declare function Currying
Solution by pageword #31438
type Curryed<A extends any[], R> =
A extends [] ? () => R :
A extends [infer SingleArg] ? (arg: SingleArg) => R :
A extends [infer SingleArg, ...infer Rest] ? (arg: SingleArg) => Curryed<Rest, R>
: never;
declare function Currying<T extends Function>(fn: T): T extends (...args: infer A) => infer R ? Curryed<A,R> : never
一开始我是这样写的
type Curryed<A extends any[], R> =
A extends [] ? () => R :
A extends [infer SingleArg] ? (arg: SingleArg) => R :
A extends [infer SingleArg, ...infer Rest] ? (arg: SingleArg) => Curryed<Rest, R>
: never;
declare function Currying<A extends any[], R extends any>(fn: (...args: A) => R): Curryed<A,R>
但不知道为啥这样写会把 Currying(() => true)
的参数识别为 () => boolean0
Solution by AEPKILL #31326
type Curried<F> = F extends (...args: infer A) => infer R
? A['length'] extends 0 | 1
? F
: A extends [infer HEAD, ...infer TAIL]
? (a: HEAD) => Curried<(...args: TAIL) => R>
: R
: never
declare function Currying<F>(fn: F): Curried<F>
Solution by Restart20200301 #31158
// your answers
type Shift<T extends any[]> = T extends [infer F, ...infer Rest] ? Rest : never;
declare function Currying<T extends Function>(fn: T):
T extends (...params: infer Params) => infer R
? Params['length'] extends 0 ? () => ReturnType<T>
: Params['length'] extends 1
? (p: Params[0]) => ReturnType<T>
: (p: Params[0]) => ReturnType<typeof Currying<(...nextFnParams: Shift<Params>) => R>>
: never;
Solution by kakasoo #30983
type Curry<T extends any[], F> = T extends [infer CURR, ...infer NEXT] ? (arg0: CURR) => Curry<NEXT, F> : F;
declare function Currying<P extends any[], R extends boolean>(fn: (...val: P) => R): Parameters<typeof fn> extends [] ? () => R : Curry<Parameters<typeof fn>, R>;
Solution by ickynavigator #30751
declare function Currying<F>(fn: F): F extends (...args: infer Rest) => infer B ? Rest extends [] ? () => B : CurryResult<Rest,B> : never;
type CurryResult<Arg,Res> = Arg extends [infer First, ...infer Rest] ?
(arg: First) => CurryResult<Rest,Res> : Res;
Solution by GrinZero #30618
type CuuryedArgs<Args extends unknown[], Ret> = Args['length'] extends 0
? () => Ret
: Args extends [infer F, ...infer Rest]
? Rest['length'] extends 0 ? (a: F) => Ret : (a: F) => CuuryedArgs<Rest, Ret>
: never;
type CurryedFunc<F extends Function> = F extends (...args: infer Args) => infer Ret
? CuuryedArgs<Args, Ret>
: never;
declare function Currying<F extends Function>(fn: F): CurryedFunc<F>
Solution by gegham1 #29445
type SmallerFunction<T> = T extends (p: any, ...q: infer R) => infer S ? (...q: R) => S : any;
type CurryingRecursive<T extends (...p: any[]) => any> =
Parameters<T>["length"] extends 0 ?
() => ReturnType<T> :
Parameters<T>["length"] extends 1 ?
(p: Parameters<T>[0]) => true :
(p: Parameters<T>[0]) => CurryingRecursive<SmallerFunction<T>>;
declare function Currying<T>(fn: T): T extends (...p: any[]) => any ? CurryingRecursive<T> : never;
Solution by spotky1004 #29368
This solution is longer but slightly better than the canonical one (#1404) in that it takes care to preserve the names of the function parameters. Extracting the first element of a tuple while preserving its label is tricky but possible thanks to @jcalz's answer to a Stack Overflow question.
// See https://stackoverflow.com/a/72244704/388951
type FirstAsTuple<T extends any[]> = T extends [any, ...infer R]
? T extends [...infer F, ...R]
? F
: never
: never
type Curried<F> = F extends (...args: infer Args) => infer Return
? Args['length'] extends 0 | 1
? F
: Args extends [any, ...infer Rest]
? (...args: FirstAsTuple<Args>) => Curried<(...rest: Rest) => Return>
: never
: never
declare function Currying<T extends Function>(fn: T): Curried<T>
Compare:
vs:
Solution by danvk #28634
type MyCurrying<T> = T extends (...args: infer A) => infer R
? A extends [infer F, ...infer L]
? L["length"] extends 0
? (arg: F) => R
: (arg: F) => MyCurrying<(...arg: L) => R>
: () => R
: T
declare function Currying<F>(fn: F): MyCurrying<F>
Solution by duanbx #28547
type Curried<T, B extends boolean = false> =
T extends (...args: infer Y) => infer P ? Y extends [infer F, ...infer R]
? (...args: [F]) => Curried<(...args: R) => P, true> : B extends true ? P : T : never;
declare function Currying<F>(fn: F): Curried<F>
Solution by smileboyi #27484
type Curry<P, R> = P extends [infer H, ...infer T] ? (p: H) => Curry<T, R> : R
// Extract the args from the generic type, if they're empty just return a function with no arguments
// Else recurisvely go through the arguments and create a function for each
declare function Currying<T extends Function>(fn: T): T extends (...args: infer Args) => infer Return
? Args extends never[]
? () => Return
: Curry<Args, Return>
: never
Solution by dec-land #27238
type GetFunctionParams<T> = T extends (...args: infer R) => unknown ? R : never;
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type GetCurryingResponseFromParams<T extends unknown[], ReturnType, IsEmpty extends boolean> = IsEmpty extends true
? () => ReturnType
: T extends [infer First, ...infer Rest]
? (arg: First) => GetCurryingResponseFromParams<Rest, ReturnType, IsEmpty>
: ReturnType;
declare function Currying<T>(
fn: T,
): GetCurryingResponseFromParams<
GetFunctionParams<T>,
GetReturnType<T>,
GetFunctionParams<T> extends [] ? true : false
>;
Solution by rldnd #27046
之前提交很多答案都没有考虑函数的参数为空的情况,因此我的代码中有对此进行额外判断,希望能对你有所帮助
Many of the answers submitted previously did not consider the case where the function's argument is empty. So my code has an additional determination for this. Hope this helps you.
declare function Currying<T>(fn: T): CurryingReturnTypeEnter<T>
type CurryingReturnTypeEnter<T> = T extends (...params: infer Params) => any
? Params['length'] extends 0
? T
: CurryingReturnType<T>
: never
type CurryingReturnType<T> = T extends (...params: infer Params) => infer Result
? Params extends [infer First, ...infer Other]
? (param: First) => CurryingReturnType<(...params: Other) => Result>
: Result
: never
Solution by CwRv07 #26700
type Unshift<T extends any[]> = T extends [infer K, ...infer U] ? U : []
type Curried<Fn> =
Fn extends (...args: infer Args) => infer Res
? Args['length'] extends 0 | 1
? (...args: Args) => Res
: (arg: Args[0]) => Curried<(...args: Unshift<Args>) => Res>
: never
declare function Currying<Fn>(fn: Fn): Curried<Fn>
Solution by WisestCoder #26468
// your answers
type Curried<T extends any[], R> = T extends [infer F, ...infer Rest]
? (arg: F) => Curried<Rest, R>
: true;
declare function Currying<T extends any[], R>(
fn: (...args: T) => R
): T["length"] extends 0 ? (...arg: T) => true : Curried<T, R>;
Solution by DvYinPo #26415
// your answers
declare function Currying<F>(fn: F): Curried<F>
type Curried<F> = F extends (args:never) => any ? F :
F extends (...args: infer A) => infer R
? A extends [infer First, ...infer Other]
? (arg: First) => Curried<(...args: Other) => R>
: R
: never;
Solution by zry666333 #26322
type ArrayToCurrying<T extends any[], Return> =
T extends [infer First, ...infer Rest]
? (x: First) => Rest extends never
? Return
: ArrayToCurrying<Rest, Return>
: Return
declare function Currying<T extends Function>(fn: T): T extends (...args: infer Args) => infer Return
? Args extends never[]
? () => Return
: ArrayToCurrying<Args, Return>
: never
Solution by Jicmou #25625
// It's possible to write it more concisely. It my first approach without cleaning the code.
type C<Head, Tail, ReturnType> = Tail extends []
? (Head: Head) => ReturnType
: Tail extends [infer THeadArray, ...(infer TTailArray)]
? (propertyName: Head) => C<THeadArray, TTailArray, ReturnType>
: ReturnType;
declare function Currying<TFnArgs>(
fn: TFnArgs,
): TFnArgs extends () => infer TFnReturnType
? () => TFnReturnType
: TFnArgs extends (...args: infer TFnArgsArray) => infer TFnReturnType
? TFnArgsArray extends [infer THeadArray, ...(infer TTailArray)]
? C<THeadArray, TTailArray, TFnReturnType>
: never
: never;
Solution by jakubjereczek #25157
// your answers
type Currying<T> = T extends (...args: [infer Left, ...infer Rest]) => infer R
? Rest['length'] extends 0
? T
: (x: Left) => Currying<(...args: Rest) => R>
: never
declare function Currying<T extends Function>(fn: T): Currying<T>
Solution by studymachiney #24953
type Currying<T extends Function> = T extends (...args: infer P) => infer R ?
P extends [infer PF, infer PS, ...infer PR] ? (arg: PF) => Currying<(...args: [PS, ...PR]) => R> : T :
never;
declare function Currying<T extends Function>(fn: T): Currying<T>;
// old way
// type Currying<T> = T extends (...args: [infer F, ...infer R]) => infer RT ?
// (R extends [] ? T :
// (arg: F) => Currying<(...args: R) => RT>) :
// never;
// declare function Currying<T>(fn: T): Currying<T>
Solution by E-uler #24574
type Curry<F> = F extends (...args: infer Args) => infer R
? Args extends [infer F1,...infer R1]
? (arg:F1) => R1 extends [] ? R: Curry<(...args:R1) => R>
: F
: never
declare function Currying<F>(fn: F): Curry<F>;
Solution by songhuige #24404
// 你的答案
type CurryingFn<Fn extends Function> = Fn extends (first:infer F,...args:infer O)=>infer R
// 参数为空
? O['length'] extends 0
? Fn
: (first:F)=> CurryingFn<(...args:O)=>R>
: never
Solution by walker-hzx #24283
// 你的答案
**第1种解法**
`typescript
declare function Currying<T>(fn: T): Fn<T>;
type Fn<T> = T extends (...args: infer Args) => infer R
? Args extends [infer P0, infer P1, ...infer P99]
? (p: P0) => Fn<(p: P1, ...p99: P99) => R>
: T
: never;
`
**第2种解法(第1种微变写法)**
`typescript
declare function Currying<T extends (...args: any) => any>(fn: T): Fn2<T>;
type Fn2<T extends (...args: any) => any> = Parameters<T> extends [infer P0,infer P1,...infer P99]
? (p: P0) => Fn2<(p: P1, ...p99: P99) => ReturnType<T>>
: T;
`
Solution by Lester1688 #23458
// your answers
type Curry<Args extends unknown[], R> =
Args extends [infer A, ...infer Rest]
? (a: A) => Curry<Rest, R>
: R
declare function Currying<Fn> (
fn: Fn,
): Fn extends (...args: infer Args) => infer R
? Args extends []
? () => R
: Curry<Args, R>
: never
Solution by snakeUni #23383