如何构造要求至少含一个属性的TypeScript非空类型?
构造至少包含一个属性的TypeScript类型
针对你提出的需求——要求一个类型允许原可选属性类型的所有值,但排除空对象,有两种通用的实现方式,不需要手动枚举所有属性组合:
方法一:映射类型+交叉类型
通过映射类型将每个属性单独设为必填,再取联合类型后与原可选类型交叉,确保至少有一个属性存在:
type NotEmpty<T> = T extends Record<string, never> ? never // 处理T本身是空类型的极端情况 : { [K in keyof T]-?: Pick<T, K> }[keyof T] & Partial<T>;
代码说明
{ [K in keyof T]-?: Pick<T, K> }:遍历T的每个属性K,生成仅包含K且K为必填的类型[keyof T]:取出上述所有类型的联合集合,得到所有"仅含单个必填属性"的类型& Partial<T>:与原可选类型交叉,允许同时存在其他可选属性- 开头的条件判断用于处理T本身无任何属性的情况,此时返回
never表示无合法值
使用示例
type T = { x?: number; y?: string; z?: number; }; let a: NotEmpty<T> = { z: 1 }; // ✅ 正常通过 a = {}; // ❌ 报错:类型 '{}' 缺少至少一个必填属性 a = { x: 2, y: "hello" }; // ✅ 正常通过
方法二:利用Exclude简化实现
如果原类型T仅包含可选对象属性(不包含null、undefined等其他类型),可以用更简洁的写法:
type NotEmpty<T> = Exclude<T, {}>;
代码说明
原类型T因所有属性可选,{}是它的子类型。Exclude<T, {}>会直接从T中排除空对象类型,剩下的就是至少包含一个属性的合法值。
使用示例
type T = { x?: number; y?: string }; let b: NotEmpty<T> = { x: 1 }; // ✅ 正常通过 b = {}; // ❌ 报错:类型 '{}' 无法赋值给 'NotEmpty<T>'
这个写法更简洁,但要注意如果T的范围包含非对象类型(比如T = {x?: number} | null),需要额外调整,避免误排除其他合法类型。
内容的提问来源于stack exchange,提问作者Yevgeniy P
相关产品推荐
相关产品推荐

