如何实现TS工具类型:必选属性+全选或全不选可选属性
解决TypeScript RequiredAndAllOrNothing工具类型的问题
你的问题出在:当用Required<R> & (Required<S> | Record<string, never>)时,Record<string, never>和Required<R>交叉后得到的类型本质上就是Required<R>,TypeScript的结构类型系统允许对象包含额外属性,所以只填部分S属性的对象依然会被判定为符合Required<R> & Record<string, never>的类型,不会触发错误。
正确的实现需要在“不设置S属性”的分支里,明确禁止出现S的任何属性,而不是用空对象类型。具体写法如下:
type RequiredAndAllOrNothing<R, S> = Required<R> & (Required<S> | { [K in keyof S]?: never });
原理说明
Required<R>确保R的所有属性必须存在且为必填;Required<S>分支要求S的所有属性必须全部设置;{ [K in keyof S]?: never }分支要求S的所有属性要么完全不存在,要么其类型为never(即无法赋值任何有效值),这样只要对象包含S的任意一个属性且有值,就会和这个类型冲突,从而被TS拦截。
验证示例
type Example = RequiredAndAllOrNothing< { aaaa: number; bbbb: boolean; cccc: boolean}, { dddd: number; eeee: boolean; ffff: boolean } >; // ✅ 符合要求:仅包含R的所有属性 const x: Example = { aaaa: 1, bbbb: true, cccc: false }; // ✅ 符合要求:包含R和S的所有属性 const y: Example = { aaaa: 1, bbbb: true, cccc: false, dddd: 1, eeee: true, ffff: false }; // ❌ 不符合要求:仅设置了S的部分属性,类型报错 const z: Example = { aaaa: 1, bbbb: true, cccc: false, dddd: 1 };
修正你的AllOrNothing类型
你之前的AllOrNothing<T>其实也存在同样的潜在问题(测试部分属性时会失效),正确的写法应该是:
type AllOrNothing<T> = Required<T> | { [K in keyof T]?: never };
内容的提问来源于stack exchange,提问作者v-moe
相关产品推荐
相关产品推荐

