如何在TypeScript中键入自动货币

如何在TypeScript中键入自动货币,typescript,functional-programming,typescript-typings,currying,Typescript,Functional Programming,Typescript Typings,Currying,我正在尝试为以下函数编写类型: const curry=( f、 arr=[] )=>(…参数)=>( a=>a.length>=f.length? f(…a): 咖喱(f,a) )([…arr,…args]); 我发现它为curry创建了如下类型: type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never; type Tail<T extends any[]> = ((

我正在尝试为以下函数编写类型:

const curry=(
f、 arr=[]
)=>(…参数)=>(
a=>a.length>=f.length?
f(…a):
咖喱(f,a)
)([…arr,…args]);
我发现它为
curry
创建了如下类型:

type Head<T extends any[]> =
  T extends [any, ...any[]]
  ? T[0]
  : never;

type Tail<T extends any[]> =
  ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)
  ? TT
  : [];

type HasTail<T extends any[]> =
  T extends ([] | [any])
  ? false
  : true;

type Curry<P extends any[], R> = 
  (arg: Head<P>) => HasTail<P> extends true
  ? Curry<Tail<P>, R>
  : R;
function curry<P extends any[], R>(f: (...args: P) => R): Curry<Required<P>, R> {
  const _curry = (
    f: (...args: any) => any, arr: any[] = []
  ) => (...args: any) => (
    a => a.length >= f.length ?
      f(...a) :
      _curry(f, a)
  )([...arr, ...args]);
  return _curry(f);
}
类型头=
T扩展[any,…any[]
? T[0]
:从不;
型尾=
((…t:t)=>any)扩展((…any,…tail:infertt)=>any)
? TT
: [];
HasTail型=
T扩展([]|[任何])
? 假的
:正确;
类型Curry=
(arg:Head

)=>HasTail

扩展为true ? 咖喱 :R;

我的问题是,这个
Curry
类型的签名与我的
Curry
函数的签名不匹配(或者我的TypeScript技能太差了吗?)。此外,我不知道如何为
curry
编写与
curry
类型匹配的实现

如何实现my
curry
的类型?使用
Curry
类型的实现会是什么样子呢?

这里有一个主要的警告:很奇怪;它只适用于没有默认参数或rest参数的函数。例如,根据TS编译器所针对的JS版本,您可能会得到以下代码的不同答案:

console.log(((arg = 1) => { }).length); // 0? 1?
所以,当您使用依赖于函数参数长度的运行时反射的任何东西时,请记住这一点


您的
curry()
函数可分配给
curry
类型定义,但反之亦然。如果基础函数仍然需要参数,则
Curry
类型定义每次调用时只需要一个参数,而
Curry
在调用时将接受任意数量的参数。这意味着我们可以给
curry()
指定
curry
类型,但是编译器会限制调用它的参数数量。它可能是这样的:

type Head<T extends any[]> =
  T extends [any, ...any[]]
  ? T[0]
  : never;

type Tail<T extends any[]> =
  ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)
  ? TT
  : [];

type HasTail<T extends any[]> =
  T extends ([] | [any])
  ? false
  : true;

type Curry<P extends any[], R> = 
  (arg: Head<P>) => HasTail<P> extends true
  ? Curry<Tail<P>, R>
  : R;
function curry<P extends any[], R>(f: (...args: P) => R): Curry<Required<P>, R> {
  const _curry = (
    f: (...args: any) => any, arr: any[] = []
  ) => (...args: any) => (
    a => a.length >= f.length ?
      f(...a) :
      _curry(f, a)
  )([...arr, ...args]);
  return _curry(f);
}
看起来不错


至于如何为
curry()
的完整版本(每次可能有多个args)创建TS类型,它需要类型级别的元组连接,但目前不直接支持()。您可以编写一些涉及递归条件类型的代码,但由于递归类型也不受直接支持(),因此我不建议将它们用于生产系统

或者你可以选择一些最大长度来支持,比如说,一次支持三个参数,然后编写一个版本的
Curry
来实现这一点,但我不知道这是否真的值得:

type Curry3<P extends any[], R> = P extends [] ? R : (
  ((a0: Head<P>) => Curry3<Tail<P>, R>) & (
    P extends [any] ? unknown : (
      ((a0: Head<P>, a1: Head<Tail<P>>) => Curry3<Tail<Tail<P>>, R>) & (
        P extends [any, any] ? unknown : (
          ((a0: Head<P>, a1: Head<Tail<P>>, a2: Head<Tail<Tail<P>>>) =>
            Curry3<Tail<Tail<Tail<P>>>, R>)
        )
      )
    )
  )
);
类型Curry3=P扩展[]?R:(
((a0:Head

)=>Curry3)和( P扩展[任何]?未知:( ((a0:Head

,a1:Head)=>Curry3)和( P扩展[任何,任何]?未知:( ((a0:Head

,a1:Head,a2:Head)=> 咖喱(3) ) ) ) ) );

特别是因为这个特定的定义使用了可能并不适用于任何地方的术语

无论如何,希望这有帮助;祝你好运