在 TypeScript 中,当你尝试将一个对象传递给一个函数或赋值给一个变量时,如果对象的属性不完全符合接口或类型的定义,你会收到一个错误。但是,TypeScript 对额外的属性(不在接口或类型定义中的属性)和缺失的属性有不同的处理方式。
- 为什么只提示了
name1
没有声明的错误,没有 age
的错误提示?
* **额外的属性**:当你尝试将一个对象传递给一个函数或赋值给一个变量时,如果该对象有额外的属性(即不在接口或类型定义中的属性),TypeScript 通常会忽略这些额外的属性,并不会报错。这是 TypeScript 的一种设计选择,旨在允许一定程度的灵活性。在你的例子中,`age` 是一个额外的属性,因此 TypeScript 没有报错。
* **缺失的属性**:相反,如果对象缺少接口或类型定义中的属性,TypeScript 会报错。在你的例子中,`IPerson` 接口定义了 `name` 和 `others` 属性,但没有定义 `name1` 属性,所以当你尝试传递一个包含 `name1` 属性的对象时,TypeScript 会报错。
- 为什么把字面量形式的对象赋值给
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 对额外的属性和缺失的属性有不同的处理方式,这导致了你所观察到的错误提示不一致的现象。
区别在于前者你是直接传了一个字面量进去,后者是通过一个中间变量(且未声明类型)传入的。
对于前者而言 TS 的类型检查会更严格,这一特性叫 Freshness(默认开启,可通过 tsconfig.json 里的
suppressExcessPropertyErrors
配置项关闭)。而后者就是普通的鸭子类型检查。至于为啥有这种特性,感兴趣可以自己搜索了解。
P.S. 问题一并不是个问题,只是 TS 报错是一种“懒检查”,即同类型的错误已经检查到了后面就跳过了,这样能显著地加快检查速度。你把 name1 删了就能看到 age 也一样报错了。