Typescript类型定义与推理



在下面的例子中:

操场上联系

type Foo = () => void;
let a: Foo | undefined = undefined;
const c = () => { a = () => console.log("Hi!") };
c();
if (a) {
a();
}

在第4行,a的类型是let a: Foo | undefined,但在第8行,它是let a: never。因此,tsc显示了这个错误:Type 'never' has no call signatures在第8行。

但是如果第2行是let a: Foo | undefined;(去掉变量赋值)

我猜是和类型推断有关的东西。文档声明:

在TypeScript中,有几个地方使用了类型推断在没有显式类型注释时提供类型信息。

let x = 3;
^
let x: number

但是在这个例子中有一个显式的类型注释

我理解TS无法知道函数c是否将被执行,因此,a将被分配。这就是为什么我把a类型的显式定义放在它的声明中。

那么为什么在第8行不尊重为a定义的类型?

这是不合理的行为,正如你在你的问题中所指出的。该行为在GitHub问题跟踪器上的一个公开问题中被注意到,题为"控制流分析中的权衡":

乐观:本地行为不良

TypeScript编译器有这样的代码:
enum Token { Alpha, Beta, Gamma }
let token = Token.Alpha;
function nextToken() {
token = Token.Beta;
}
function maybeNextToken() {
if (... something ...) {
nextToken();
}
}
function doSomething() {
if (token !== Token.Alpha) {
maybeNextToken();
}
// is this possible?
if (token === Token.Alpha) {
// something happens
}
}

乐观地假设token没有被maybeNextToken修改,错误地将token === Token.Alpha标记为不可能。然而,在其他情况下,这是一个很好的检查!参见后面的示例。

问题是,在其他情况下,使编译器更悲观将是有害的,因为编译器将无法检测到代码中的真正错误。在写这个答案的时候,这个问题已经超过5年了,仍然没有解决,看起来语言设计者们还没有就是否需要做些什么达成一致,或者如果需要做些什么。

最新更新