【问题标题】:Why do subtypes need to be assigned to a variable before being used as a function argument?为什么在用作函数参数之前需要将子类型分配给变量?
【发布时间】:2021-08-31 11:33:31
【问题描述】:

我正在学习子类型,想知道为什么这里给出的示例 https://www.typescriptlang.org/docs/handbook/type-compatibility.html 可以编译,但是当我将子类型作为参数直接传递给函数时,它不会编译。

这是来自 typescriptlang.org 的原始代码

interface Named {
    name: string;
}

let x: Named;
// y's inferred type is { name: string; location: string; }
let y = { name: "Alice", location: "Seattle" };


function greet(n: Named) {
    console.log("Hello, " + n.name);
}
greet(y); // OK

编译得很好。但是这个版本,子类型没有分配给 y,失败了。

interface Named {
    name: string;
}

let x: Named;

function greet(n: Named) {
    console.log("Hello, " + n.name);
}
greet({ name: "Alice", location: "Seattle" }); // NOT OK

我得到错误:

类型参数 '{ name: string;位置:字符串; }' 不可分配给“命名”类型的参数。对象字面量只能指定已知属性,而“命名”类型中不存在“位置”。

为什么必须先将子类型 { name: "Alice", location: "Seattle" } 分配给变量?

【问题讨论】:

  • 它被称为多余的属性检查,只有当你为给定类型的参数分配一个新的对象字面量时才会触发它。
  • Titian Cernicova-Dragomir 已经给了你答案,但你应该查看官方文档以获得更深入的解释:typescriptlang.org/docs/handbook/interfaces.html 另外,如果你不想使用变量,还有另一个选项: greet({ name: "Alice", location: "Seattle" } as Named);

标签: typescript subtyping


【解决方案1】:

这是因为当您在需要特定类型的地方使用“新”对象字面量(即尚未分配给变量的字面量)时,通常会添加一个错误类型中未提及的属性。所以这通过excess property checking 被标记为错误。它是少数几个将类型视为“封闭”或"exact" 而不是“开放”的地方之一。

有一些变通方法可以解决您并非要进行过多的属性检查的情况。一种是在n 参数的类型中添加index signature,这样所有额外的属性都可以接受:

function greet(n: Named & { [x: string]: unknown }) {
  console.log("Hello, " + n.name);
}
greet({ name: "Alice", location: "Seattle" }); // okay

或者,如果您通常希望进行此类检查,但只想使用该特定对象字面量调用 greet(),则可以使用 type assertion 来避免中间变量:

greet({ name: "Alice", location: "Seattle" } as Named); // okay

这取决于你。好的,希望有帮助;祝你好运!

【讨论】:

  • 真的很奇怪,将对象分配给另一个变量会绕过检查。
  • 您可以阅读original pull request 详细说明其工作原理。看起来意图是应该捕获额外的属性而不是静默丢弃。如果您分配给另一个变量,则该变量的推断类型将具有额外的属性。之后,如果您将它传递给期望更广泛类型的东西,他们会认为您打算这样做。
猜你喜欢
  • 2019-08-26
  • 2020-08-20
  • 1970-01-01
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多