我必须为TypeScript中的高阶函数类型指定参数名称吗?

Tha*_*you 8 higher-order-functions typescript

试图使用TypeScript弄湿我的脚,但我一直遇到麻烦今天,一个旧功能浮出水面,并且作为练习,我很好奇是否可以将其转换为TypeScript。到目前为止,颈部已经完全疼痛。

declare type Ord = number | string;

// type signature for f sucks really bad
// (f: Ord => Ord => boolean) would be really nice, if possible
// but instead I have to give names (_) for the parameters? dumb
const arrayCompare = (f: (_: Ord) => (_: Ord) => boolean) => ([x,...xs]: Ord[]) => ([y,...ys]: Ord[]): boolean => {
  if (x === undefined && y === undefined)
    return true;
  else if (! f (x) (y))
    return false;
  else
    return arrayCompare (f) (xs) (ys);
}

// here the names of the parameters are actually used
const eq = (x: Ord) => (y: Ord) : boolean => x === y;

// well at least it works, I guess ...
console.log(arrayCompare (eq) ([1,2,3]) ([1,2,3]));             // true
console.log(arrayCompare (eq) (['a','b','c']) (['a','b','c'])); // true
Run Code Online (Sandbox Code Playgroud)

因此,问题特别是关于(请参阅粗体

const arrayCompare = (f: (_: Ord) => (_: Ord) => boolean) => ...
Run Code Online (Sandbox Code Playgroud)

f 期望该类型的高阶函数

Ord => Ord => boolean
Run Code Online (Sandbox Code Playgroud)

但是如果我使用这种类型签名

// danger !! unnamed parameters
(f: (Ord) => (Ord) => boolean)
Run Code Online (Sandbox Code Playgroud)

TypeScript将假定Ord为参数名称,隐式类型为any

// what TypeScript thinks it means
(f: (Ord: any) => (Ord: any) => boolean)
Run Code Online (Sandbox Code Playgroud)

当然,这不是我想要的,但是无论如何,这就是我得到的。为了获得我真正想要的,我必须为高阶函数指定参数的名称

// now it's correct
(f: (_: Ord) => (_: Ord) => boolean)
Run Code Online (Sandbox Code Playgroud)

但这没什么意义。f在这种情况下,我只能访问,而f在我最终调用它时将无法绑定的参数...

为什么必须在TypeScript中为高阶函数参数提供名称

这没有任何意义,并且会使函数签名冗长,丑陋,难于编写和难于阅读。


更新

“就参数名称而言,请考虑采用->(数字->数字->数字)->的回调的函数,因此,仅基于您选择的类型:加,减,乘,除,幂,比较其中只有一个是有意义的,现在,如果回调参数具有名称添加:(数字->数字->数字),选择将是显而易见的”Aleksey Bykov

我很高兴有机会对此进行回复。我可以使用(number -> number -> number)签名命名更多的函数。

  • firstsecondmodminmax
  • 按位函数&|xor<<,和>>
  • (x, y) => sqrt(sq(x) + sq(y))
  • (x, y) => x + x + y + y + superglobalwhocares
  • 以及您可以梦想的任何其他功能

为了清楚起见,我不建议不要给函数参数本身起一个名字。我建议不要给函数参数的参数起个名字...

// this
func = (f: (number => number => number)) => ...

// not this
func = (f: (foo: number) => (bar: number) => number)) => ...
Run Code Online (Sandbox Code Playgroud)

为什么?很好,因为f不了解我将要提供的功能参数。

// for the record, i would never name parameters like this
// but for those that like to be descriptive, there's nothing wrong with these
const add = (addend: number) => (augend: number) => number ...
const sub = (minuend: number) => (subtrahend: number) => number ...
const divide = (dividend: number) => (divisor: number) => number ...
const mult = (multiplicand: number) => (multiplier: number) => number ...

// I could use any of these with my func
func (add ...)
func (sub ...)
func (divide ...)
func (mult ...)
Run Code Online (Sandbox Code Playgroud)

如果尝试尝试,我将无法提供f参数的名称func!因为谁知道我将使用哪个功能?所有这些都是适当的。

如果我尝试在其上加上名称,则会使用户无法想象该功能的功能。

// maybe the user thinks only a division function can be specified (?)
func = (f: (dividend: number) => (divisor: number) => number) => ...
Run Code Online (Sandbox Code Playgroud)

dividenddivisor不是一个不错的选择这里,是因为上面列出的任何功能将适合。在最好的我能做到这一点

// provide generic name for f's parameters
func = (f: (x: number) => (y: number) => number) => ...
Run Code Online (Sandbox Code Playgroud)

但是那有什么意义呢?它不像xy成为绑定标识符。而xy报价不加说明-我想使我想到我的观点:他们不意味着有一个名称或说明。f具有的我们可能会使用它的方式的知识,但它并不重要; 只要有(number => number => number)接口,这就是我们关心的全部。这就是我们可以向用户提供有关参数的有用的信息。funcf

“对于这样的功能,这将非常令人困惑:

foo(cb: (number, number) => (number, string) => boolean)
Run Code Online (Sandbox Code Playgroud)

它是做什么的?” - 工会

此处使用相同的确切推理。除了(cb: (number, number) => (number, string) => boolean))功能设计不佳的事实(您可以命名几个有用的混合类型四元(4参数)函数?)外,这也没有关系。f不能假装知道使用此类签名可以提供的无数函数的任何描述符。

所以我的问题是,为什么我必须为函数参数参数指定明显无意义的名称?


行使

您可以_用有意义的名称代替吗?

const apply2 = (f: (_: number) => (_: number) => number) => (x: number) => (y: number): number => {
    return f (x) (y)
};

const sqrt = (x: number): number => Math.sqrt(x);
const sq = (x: number): number => x * x;
const add = (addend: number) => (augend: number): number => addend + augend;
const pythag = (side1: number) => (side2: number): number => sqrt(add(sq(side1)) (sq(side2)));

console.log(apply2 (add) (3) (4));    // 7
console.log(apply2 (pythag) (3) (4)); // => 5
Run Code Online (Sandbox Code Playgroud)

如果不是,您是否可以提出令人信服的论点,为什么在TypeScript签名中必须出现这样的名称?

Nit*_*mer 3

编写柯里化定义是很困难的,至少以可读的方式是这样。
我要做的就是尽可能地提取函数声明之外的签名,如下所示:

type Ord = string | number;
type ThirdFunction = (objs: Ord[]) => boolean;
type SecondFunction = (objs: Ord[]) => ThirdFunction;
type FirstFunction = (fn: (o: Ord) => (o: Ord) => boolean) => SecondFunction;

const arrayCompare: FirstFunction = f => ([x,...xs]) => ([y,...ys]) => {
    ...
}
Run Code Online (Sandbox Code Playgroud)

操场上的代码

我还删除了declare您之前的Ord类型别名,不需要它。您还可以为这些类型找到更好的名称。
另一件事是您不需要在boolean此处指定:

const eq = (x: Ord) => (y: Ord) : boolean => x === y;
Run Code Online (Sandbox Code Playgroud)

可:

const eq = (x: Ord) => (y: Ord) => x === y;
Run Code Online (Sandbox Code Playgroud)

或者您可以使用单个type声明来表达该函数。考虑到所有因素,可读性相当不错。

type Ord = number | string;

type arrayCompareFunc = (f: (x: Ord) => (y: Ord) => boolean)
                      => (xs: Ord[])
                      => (ys: Ord[])
                      => boolean;

const arrayCompare: arrayCompareFunc = f => ([x,...xs) => ([y,...ys) => {
   ...
};
Run Code Online (Sandbox Code Playgroud)