TypeScript中Human联合类型为何允许含部分Extra字段的无效实例?
问题原因
你遇到的问题本质是TypeScript联合类型的可赋值性规则导致的:
- 联合类型
Human = Base | (Base & Extra)的判断逻辑是:只要值能赋值给联合类型中的任意一个分支,就会被视为有效。 {id: "123", firstName: "Seppo"}虽然包含了firstName,但它完全符合Base类型的要求(只需要有id属性)——TypeScript默认允许对象拥有额外属性,除非开启额外属性检查(但额外属性检查只在直接给对象字面量赋值给具体接口时触发,联合类型场景下不会生效)。所以TS判定这个值可以赋值给Base分支,自然就通过了类型校验。
解决方法
如果你想严格限制Human要么是仅包含Base字段的对象,要么是包含Base+Extra所有字段的对象,可以通过以下方式实现:
方法1:使用精确类型约束
通过交叉一个“禁止额外属性”的类型来定义严格的Base分支:
interface Base { id: string; } interface Extra { firstName: string; lastName: string; } // 定义严格的Base,禁止拥有Extra中的字段 type StrictBase = Base & { [K in keyof Extra]?: never }; type Human = StrictBase | (Base & Extra); const validBase: Human = { id: "123" }; // 有效 const validHuman: Human = { id: "123", firstName: "Seppo", lastName: "Taalasmaa" }; // 有效 const shouldBeInvalid: Human = { id: "123", firstName: "Seppo" }; // 类型错误:firstName不能为string类型
方法2:添加判别式字段
如果业务允许,可以给两个分支添加一个区分用的判别字段,让TS能明确区分不同分支:
interface Base { id: string; type: "base"; } interface FullHuman extends Base { type: "full"; firstName: string; lastName: string; } type Human = Base | FullHuman; const validBase: Human = { id: "123", type: "base" }; // 有效 const validHuman: Human = { id: "123", type: "full", firstName: "Seppo", lastName: "Taalasmaa" }; // 有效 const shouldBeInvalid: Human = { id: "123", type: "full", firstName: "Seppo" }; // 类型错误:缺少lastName字段
这种方式更直观,也更符合TypeScript的类型设计思路,推荐在有业务场景支撑时使用。
内容的提问来源于stack exchange,提问作者Jarzka
相关产品推荐
相关产品推荐

