TypeScript 中未声明属性错误提示不一致?

如下代码:

interface IPerson {
  name: string;
  others: { hobby: string };
}

function testFn(type: IPerson) {
  console.log("🚀 ~ testFn ~ type:", type);
}

testFn({ name: "123", age: 18, others: { hobby: "跑步", name1: "124" } });

const p1 = { name: "123", age: 18, others: { hobby: "跑步", name1: "124" } };
testFn(p1);

在 vs code 中,有一个报错提示:
image.png

我有2个疑问:

  1. 为什么 age、name1 都没有在 IPerson 中声明,但只提示了 name1 没有声明的错误,没有 age 的错误提示?
  2. 把字面量形式的对象赋值给 p1 变量,然后传给 testFn,为啥此时没有任何错误提示了呢?

尝试将这段代码放在多个地方,排除了 tsconfig.json 配置的原因。

阅读 370
avatarAI BotBETA

在 TypeScript 中,当你尝试将一个对象传递给一个函数或赋值给一个变量时,如果对象的属性不完全符合接口或类型的定义,你会收到一个错误。但是,TypeScript 对额外的属性(不在接口或类型定义中的属性)和缺失的属性有不同的处理方式。

  1. 为什么只提示了 name1 没有声明的错误,没有 age 的错误提示?
* **额外的属性**:当你尝试将一个对象传递给一个函数或赋值给一个变量时,如果该对象有额外的属性(即不在接口或类型定义中的属性),TypeScript 通常会忽略这些额外的属性,并不会报错。这是 TypeScript 的一种设计选择,旨在允许一定程度的灵活性。在你的例子中,`age` 是一个额外的属性,因此 TypeScript 没有报错。
* **缺失的属性**:相反,如果对象缺少接口或类型定义中的属性,TypeScript 会报错。在你的例子中,`IPerson` 接口定义了 `name` 和 `others` 属性,但没有定义 `name1` 属性,所以当你尝试传递一个包含 `name1` 属性的对象时,TypeScript 会报错。
  1. 为什么把字面量形式的对象赋值给 p1 变量,然后传给 testFn 时没有任何错误提示了呢?
* 当你将字面量形式的对象赋值给 `p1` 变量时,TypeScript 会尝试推断 `p1` 的类型。由于字面量对象具有 `name`、`age` 和 `others` 属性,TypeScript 会推断 `p1` 的类型为 `{ name: string; age: number; others: { hobby: string; name1: string } }`。
* 当你将 `p1` 传递给 `testFn` 函数时,TypeScript 会比较 `p1` 的类型(即 `{ name: string; age: number; others: { hobby: string; name1: string } }`)和 `testFn` 函数的参数类型(即 `IPerson`)。由于 `IPerson` 只定义了 `name` 和 `others` 属性,而 `p1` 的类型包含了这两个属性以及额外的 `age` 属性,因此 TypeScript 不会报错。如前所述,TypeScript 允许额外的属性。

总的来说,TypeScript 对额外的属性和缺失的属性有不同的处理方式,这导致了你所观察到的错误提示不一致的现象。

1 个回答

区别在于前者你是直接传了一个字面量进去,后者是通过一个中间变量(且未声明类型)传入的。

对于前者而言 TS 的类型检查会更严格,这一特性叫 Freshness(默认开启,可通过 tsconfig.json 里的 suppressExcessPropertyErrors 配置项关闭)。而后者就是普通的鸭子类型检查。

至于为啥有这种特性,感兴趣可以自己搜索了解。

P.S. 问题一并不是个问题,只是 TS 报错是一种“懒检查”,即同类型的错误已经检查到了后面就跳过了,这样能显著地加快检查速度。你把 name1 删了就能看到 age 也一样报错了。

logo
Microsoft
子站问答
访问
宣传栏