为何TypeScript中两种NonNullableCopy实现效果存在差异?
两种NonNullableCopy实现的行为差异解析
第一种失效的实现
type NonNullableCopy<O> = { [p in keyof O] -?: O[p] extends null | undefined ? never : O[p]; }; type Adsa = {a?: number | null} type Basda = NonNullableCopy<Adsa> let asd : Basda = { a: null // 仍合法,无报错 }
第二种生效的实现
type NonNullable<T> = T extends null | undefined ? never : T; type NonNullableCopy<O> = { [p in keyof O] -?: NonNullable<O[p]>; }; type Adsa = {a?: number | null} type Basda = NonNullableCopy<Adsa> let asd : Basda = { a: null // 生效,抛出错误 }
差异核心:条件类型的分布式特性
两者的行为差异本质是是否触发分布式条件类型:
第一种实现的问题
原类型Adsa的a属性实际是number | null | undefined(可选属性会自动包含undefined类型)。第一种实现的条件判断是对整个联合类型做匹配:number | null | undefined是否完全属于null | undefined?显然不成立,所以条件分支直接返回O[p]本身,也就是number | null | undefined。加上-?移除可选性后,最终a的类型是number | null,因此赋值null不会报错。第二种实现的逻辑
第二种实现将条件判断抽成了独立的泛型类型NonNullable<T>,这里的T是裸类型参数(未被对象、数组等结构包裹),满足分布式条件类型的触发规则:当传入的T是联合类型时,TypeScript会自动拆分联合类型的每个成员单独判断,再将结果合并为新的联合类型。
针对O[p]即number | null | undefined:
number经过判断后保留为numbernull经过判断后变为neverundefined经过判断后变为never
合并结果为number,加上-?移除可选性后,a的类型最终是number,因此赋值null会触发类型错误。
内容的提问来源于stack exchange,提问作者Sunwarder
相关产品推荐
相关产品推荐

