TypeScript泛型combineValues函数如何约束入参属性与类型合法性
问题解决方案
我们需要对combineValues的泛型定义做两处核心修改,分别对应你提到的两个问题:
- 排除属性值的
undefined合法类型,禁止传入undefined - 增加参数合并后的完整性校验,保证
T的所有必选属性都被传入
修改后的完整代码
interface Person { name: string; age: number; } // 泛型辅助类型:递归合并所有传入参数的属性 type MergeArgs<T, Args extends any[]> = Args extends [infer First, ...infer Rest] ? First & MergeArgs<T, Rest> : {}; // 泛型辅助类型:校验合并后的属性是否完全匹配T的要求 type IsValidMerge<T, Merged> = [keyof Merged] extends [keyof T] ? (T extends Merged ? true : false) : false; class Result<T> { readonly value: T; private constructor(value: T) { this.value = value; } public static combineValues< T, Args extends Array<{ [K in keyof T]?: Exclude<Result<T[K]> | T[K], undefined> }> >(...args: Args & (IsValidMerge<T, MergeArgs<T, Args>> extends true ? Args : never)): Result<T> { // 原有逻辑实现 const merged = {} as T; for (const arg of args) { Object.assign(merged, Object.fromEntries( Object.entries(arg).map(([k, v]) => [k, v instanceof Result ? v.value : v]) )) } return new Result<T>(merged); } }
问题解决说明
1. 禁止undefined传入的实现
原来的属性定义[key in keyof T]?: Result<T[key]> | T[key]中,可选属性默认允许赋值为undefined,我们通过Exclude<Result<T[K]> | T[K], undefined>将undefined从合法类型中剔除,只要某属性被显式赋值为undefined就会触发编译错误。
2. 必选属性完整性校验的实现
我们通过两个辅助类型完成校验:
MergeArgs:递归合并所有传入参数对象的属性,得到合并后的总类型IsValidMerge:校验合并后的类型是否完全覆盖T的所有属性,且属性类型完全匹配- 最终通过参数约束
Args & (IsValidMerge<T, MergeArgs<T, Args>> extends true ? Args : never),只要合并结果不满足T的要求就会抛出编译错误
错误场景验证
传入undefined的场景
// 触发编译错误:类型undefined不能分配给类型Result<number> | number const res = Result.combineValues<Person>( { age: undefined }, { name: 'John Doe' } );
缺少必填属性的场景
// 触发编译错误:参数类型不满足约束,缺少必选属性name const res = Result.combineValues<Person>( { age: 18 } );
正常调用场景
// 编译正常 const res = Result.combineValues<Person>( { age: 18 }, { name: 'John Doe' } );
内容的提问来源于stack exchange,提问作者George Panainte
相关产品推荐
相关产品推荐

