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

2023-12-10

我正在学习子类型,并且想知道为什么这里给出一个例子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;位置:字符串; }' 不可分配给“Named”类型的参数。对象文字只能指定已知属性,并且“Named”类型中不存在“location”。

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


这是因为当您在需要特定类型的地方使用“新鲜”对象文字(意味着尚未分配给变量的对象文字)时,它是often添加类型中未提及的属性时出错。所以这被标记为错误超额财产检查。这是少数几个将类型视为“封闭”或“精确”的地方之一(如微软/TypeScript#12936与“开放”相对。

如果您不想进行过多的财产检查,有一些解决方法。一种是添加一个索引签名的类型n参数,以便所有额外的属性都是可接受的:

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

或者,如果您通常想要进行此类检查但只想致电greet()对于该特定对象文字,您可以使用类型断言避免中间变量:

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

由你决定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐