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

Why do subtypes need to be assigned to a variable before being used as a function argument?

我正在学习子类型,想知道为什么此处给出的示例 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' 类型的参数。对象字面量只能指定已知属性,并且 'location' 不存在于类型 'Named'.

为什么subtype { name: "Alice", location: "Seattle" } 必须先赋值给一个变量?

这是因为当你在需要特定类型的地方使用“新”对象字面量(意思是尚未分配给变量的字面量)时,经常 添加类型中未提及的属性时出错。因此,这通过 excess property checking. It's one of the few places where a type is treated as "closed" or "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

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