为什么在用作函数参数之前需要将子类型分配给变量?

时间:2019-05-06 14:45:57

标签: typescript subtyping

我正在学习子类型,并且想知道为什么这里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

我得到了错误:

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

为什么必须首先将子类型{名称:“ Alice”,位置:“ Seattle”}分配给变量?

1 个答案:

答案 0 :(得分:2)

这是因为当您在需要特定类型的地方使用“新鲜”对象文字(表示尚未分配给变量的对象文字)时,通常会添加错误 类型中未提及的属性。因此,通过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

由您决定。好的,希望能有所帮助;祝你好运!