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

不启用strictNullChecks时,如何将接口可空属性设为可选?

问题描述

假设有如下接口:

interface iUser {
  id: string;
  username: string;
  password: string;
  phone: string | null;
  age: number | null;
}

需要实现一个泛型NullableOptional<T>,将接口中所有**显式声明为可空(包含null联合类型)**的属性设为可选,但保留其可赋值为null的特性,最终得到:

type CreateUser = NullableOptional<iUser>;
// 等价于:
type CreateUser = {
  id: string;
  username: string;
  password: string;
  phone?: string | null;
  age?: number | null 
}

此前参考的方案依赖strictNullChecks配置,代码如下:

type PickNullable<T> = {
  [P in keyof T as null extends T[P] ? P : never]: T[P]
}

type PickNotNullable<T> = {
  [P in keyof T as null extends T[P] ? never : P]: T[P]
}

type OptionalNullable<T> = {
  [K in keyof PickNullable<T>]?: Exclude<T[K], null>
} & {
  [K in keyof PickNotNullable<T>]: T[K]
}

但在未启用strictNullChecks时,null extends T[P]会对所有属性返回true(该模式下所有类型都隐式包含null/undefined),导致PickNullable<T>等于原类型,PickNotNullable<T>为空对象,无法满足需求。


解决方案(不启用strictNullChecks)

核心思路是通过类型标注的字面信息识别显式可空属性,而非依赖类型系统的null兼容性判断。利用TS的条件类型实现:

// 辅助类型:判断类型是否显式包含null联合
type IsExplicitNullable<T> = T extends null ? true : 
  T extends infer U | null ? true : false;

// 实现NullableOptional泛型
type NullableOptional<T> = 
  // 保留非显式可空属性的必选性
  { [K in keyof T as IsExplicitNullable<T[K]> extends false ? K : never]: T[K] } &
  // 将显式可空属性设为可选,保留原类型(包含null)
  { [K in keyof T as IsExplicitNullable<T[K]> extends true ? K : never]?: T[K] };

验证效果

将泛型应用到iUser后,可正常满足需求:

type CreateUser = NullableOptional<iUser>;

// 合法赋值示例
const validUser1: CreateUser = { id: "1", username: "foo", password: "bar" };
const validUser2: CreateUser = { id: "1", username: "foo", password: "bar", phone: null };
const validUser3: CreateUser = { id: "1", username: "foo", password: "bar", age: 20 };

原理说明

  • IsExplicitNullable<T>通过两层条件判断:先识别纯null类型,再识别X | null的联合类型,精准定位显式声明的可空属性。
  • 泛型通过两个映射类型分别处理非可空和显式可空属性,再通过交叉类型合并结果,既保留了非可空属性的必选性,又保留了可空属性的null赋值能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:57:42