为何TypeScript条件类型中的infer会改变返回类型?
TypeScript条件类型中infer影响返回结果的原因
问题场景
你在使用TypeScript条件类型时遇到了如下疑问:
import { FormGroup, FormControl, AbstractControl } from '@angular/forms'; type Foo = FormGroup<{ title: FormControl<string> }> type Bar = FormGroup<{ title2: FormControl<string>; }>; type Baz = Foo | Bar extends FormGroup<infer U> ? 'ok ' : 'nok'; // 标注为NOK type Baz2 = Foo | Bar extends FormGroup ? 'ok ' : 'nok'; // 标注为OK
为何添加infer关键字后,条件类型的返回结果发生了变化?
核心原因:分布式条件类型的触发规则
TypeScript的条件类型在处理联合类型时,会根据右侧是否包含infer触发不同的行为:
1. 非分布式条件类型(无infer的情况)
当条件类型右侧不包含infer时,TypeScript会将左侧的整个联合类型作为一个整体,与右侧类型进行匹配判断。
- 比如
Baz2中,FormGroup等价于FormGroup<{}>(Angular中FormGroup的默认泛型参数),而Foo和Bar都是FormGroup的子类型,因此整个Foo | Bar联合类型满足extends FormGroup的条件,返回'ok'。
2. 分布式条件类型(含infer的情况)
当条件类型右侧包含infer,且左侧是裸联合类型时,TypeScript会自动触发分布式行为:将联合类型拆分为单个成员,分别代入条件进行判断,最后将所有结果合并为新的联合类型。
- 比如
Baz中,Foo | Bar会被拆分为Foo和Bar两个单独类型:Foo匹配FormGroup<infer U>,推断出U = { title: FormControl<string> },返回'ok'Bar匹配FormGroup<infer U>,推断出U = { title2: FormControl<string> },返回'ok'
- 最终
Baz的类型是'ok' | 'ok',即'ok'。你标注的NOK可能是笔误,或者实际场景中联合类型包含了无法匹配FormGroup<infer U>的成员(此时该成员会返回'nok',最终结果为'ok' | 'nok')。
验证案例
如果我们给联合类型加入一个非FormGroup的成员:
type Qux = string; type Baz3 = Foo | Bar | Qux extends FormGroup<infer U> ? 'ok' : 'nok'; // Baz3的类型:'ok' | 'nok'
此时分布式处理后,Qux不匹配条件返回'nok',最终结果为两种情况的联合。
对应的非分布式版本:
type Baz4 = (Foo | Bar | Qux) extends FormGroup ? 'ok' : 'nok'; // Baz4的类型:'nok'
因为整个联合类型并非全部是FormGroup的子类型,直接返回'nok'。
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

