You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何TypeScript的结构类型(鸭子类型)需要非严格联合类型?

TypeScript联合类型的非严格赋值问题

问题背景

首先定义两个类型:

type A = {
  a: string,
}

type B = {
  a: number,
  b: number,
}

以下两种单独赋值操作都会报错:

// 报错:无法赋值给A,因为A不存在属性'b'
const x: A = {
  a: 'hello',
  b: 10
}

// 报错:无法赋值给B,因为B的'a'期望number类型
const x: B = {
  a: 'hello',
  b: 10
}

根据TypeScript官方文档对联合类型的定义:

联合类型由两个或多个类型组成,表示值可以是这些类型中的任意一种。

按照这个定义,原本以为以下声明会报错,但实际并未报错:

const x: A | B = {
  a: 'hello',
  b: 10
}

这个对象字面量既无法单独赋值给A,也无法单独赋值给B,却能成功赋值给A | B。

补充信息:搜索后发现,对象字面量赋值给联合类型时,只要联合类型中有一个成员包含多余属性,就允许该属性存在。当前场景中,对象字面量满足A的类型要求,属性b是多余属性,但联合类型的另一个成员B包含该属性,因此被允许。

核心疑问:

  • 应如何理解联合类型才能解释这一结果?
  • 为什么TypeScript的结构类型系统要采用这种非严格的联合类型设计?多数开发者期望联合类型是严格的,想了解默认采用非严格设计的合理原因。

问题解答

1. 联合类型赋值逻辑的正确理解

TypeScript对对象字面量赋值给联合类型的校验规则,并非要求字面量必须完全匹配联合类型中的某一个成员,而是采用了更宽松的兼容性扩展逻辑:

  • 当对象字面量的属性满足联合类型中至少一个成员的必填属性,并且所有额外属性都能在联合类型的某个成员中找到对应定义时,赋值就会被允许。
  • 回到你的例子:对象{a: 'hello', b: 10}的a属性是字符串类型,满足A的必填属性要求;额外的b属性在B中有明确的类型定义(这里字面量的10也符合number类型要求)。因此TypeScript认为这个对象可以适配到A | B中——它既可以被视为带额外属性的A,也能在后续代码通过类型收窄处理为B(赋值时允许这种潜在兼容,后续使用时会做更严格的校验)。

2. 非严格联合类型的设计合理性

TypeScript采用这种设计,主要是为了平衡类型安全性和开发灵活性:

  • 适配真实业务场景:实际开发中常遇到对象同时具备多个类型部分属性的情况,比如接口返回的对象可能包含多种类型的字段,非严格联合类型能避免开发者被迫写冗余的类型断言。
  • 结构类型系统的特性延伸:TypeScript的结构类型(鸭子类型)核心是"具备所需属性即兼容",非严格联合类型是这一特性在联合场景下的自然延伸——允许对象拥有联合类型成员中存在的额外属性,符合鸭子类型的宽松兼容逻辑。
  • 避免过度严格的误判:如果强制要求字面量必须完全匹配某一个联合成员,会导致很多合理场景被报错。比如函数接受A | B参数,传入同时包含A必填属性和B可选属性的对象,这种用法是合理的,非严格设计可以直接支持。

内容的提问来源于stack exchange,提问作者Joseph Morgan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:16:22