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

为何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 // 生效,抛出错误
}

差异核心:条件类型的分布式特性

两者的行为差异本质是是否触发分布式条件类型:

  1. 第一种实现的问题
    原类型Adsa的a属性实际是number | null | undefined(可选属性会自动包含undefined类型)。第一种实现的条件判断是对整个联合类型做匹配:number | null | undefined是否完全属于null | undefined?显然不成立,所以条件分支直接返回O[p]本身,也就是number | null | undefined。加上-?移除可选性后,最终a的类型是number | null,因此赋值null不会报错。

  2. 第二种实现的逻辑
    第二种实现将条件判断抽成了独立的泛型类型NonNullable<T>,这里的T是裸类型参数(未被对象、数组等结构包裹),满足分布式条件类型的触发规则:当传入的T是联合类型时,TypeScript会自动拆分联合类型的每个成员单独判断,再将结果合并为新的联合类型。

针对O[p]即number | null | undefined:

  • number经过判断后保留为number
  • null经过判断后变为never
  • undefined经过判断后变为never
    合并结果为number,加上-?移除可选性后,a的类型最终是number,因此赋值null会触发类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 18:45:30