以下代码无法编译(我理解原因):
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处理这两个样本的方式不同?
答案 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来推断a
和b
的类型均为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
的某种组合?或者是其他东西?谁知道。相反,实际发生的情况是,未注释的a
和b
参数被推断为类型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.
现在,您可以通过确定您希望a
和b
是...大概是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[]
。
好的,希望能有所帮助。祝你好运!