打字稿和(a,b)=> a + b

时间:2019-01-07 01:08:09

标签: typescript

以下代码无法编译(我理解原因):

let x: number[] = [];

x = ((a, b) => a+b)(x, x);
x.push(0);

但是,它可以编译(而且我不明白为什么):

let x: number[] = [],
    f = (a, b) => a+b;

x = f(x, x);
x.push(0);

然后,如果您运行它,它将在运行时产生TypeError,就像人们期望的那样。

为什么Typescript处理这两个样本的方式不同?

1 个答案:

答案 0 :(得分:1)

我想我应该把它作为答案:

在此:

let x: number[] = [];
x = ((a, b) => a+b)(x, x);  // error
//             ~~~ <-- Operator '+' cannot be applied 
//                     to types 'number[]' and 'number[]'.
x.push(0);

匿名函数(a, b) => a + b使用contextual typing来推断ab的类型均为number[],因为您立即将其应用于该参数类型。而且由于不能在两个数组上使用+运算符,所以会出现错误。

另一方面,在此:

let x: number[] = [],
    f = (a, b) => a+b;  // f is (a: any, b: any) => any
x = f(x, x);
x.push(0);

编译器将值f的类型推断为(a, b) => a + b的类型,并且没有上下文类型化线索,因为此时尚未调用它。是的,您稍后再致电f(x, x),但打字不会像一般情况那样倒退(上下文打字本身是一种非常有限的倒退打字流程)。毕竟,您可以先呼叫f(x, x)然后再呼叫f("hey", false),然后假设f的类型需要是(a: number[], b: number[]) => any(a: string, b: boolean) => string的某种组合?或者是其他东西?谁知道。相反,实际发生的情况是,未注释的ab参数被推断为类型any。并且由于any有效地关闭了类型系统,因此a + b并不是错误。 any类型是阴险的;它往往会在程序中从一个位置静默传播到另一个位置,如果不小心,它可能会出现在您意想不到的地方。

解决此类问题的最佳方法是启用--noImplicitAny compiler option,当编译器推断出某种any类型时,它会向您发出警告。这样,您只需担心在某个地方的代码中明确记录了any类型:

let x: number[] = [],
f = (a, b) => a+b;  // error
//   ~  ~ 
//      ^--- Parameter 'b' implicitly has an 'any' type.
//   ^------ Parameter 'a' implicitly has an 'any' type.

现在,您可以通过确定您希望ab是...大概是number来解决该警告:

let x: number[] = [],
f = (a: number, b: number) => a+b;  
x = f(x, x); // error
//    ~ <-- Argument of type 'number[]' is not assignable to parameter of type 'number'.

然后您将不得不尝试显式调用f()参数上的number[]

好的,希望能有所帮助。祝你好运!