我正在学习子类型,并且想知道为什么这里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”}分配给变量?
答案 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
由您决定。好的,希望能有所帮助;祝你好运!