TypeScript结合泛型使用Omit时无法同时排除多属性的解决方法
TypeScript泛型Omit多属性联合排除实现
问题场景
需要封装一个泛型类型,默认排除实体类型上的id、collection固定属性,同时支持调用方通过泛型传入更多需要额外排除的属性。
初始实现代码如下:
type OmittedEntity<TEntity extends IBaseEntity, TExtraOmissions extends (keyof TEntity) | void = void> = TExtraOmissions extends keyof TEntity ? Omit<TEntity, "id" | "collection" | TExtraOmissions> : Omit<TEntity, "id" | "collection"> interface IBaseEntity { id: string; collection: string; status: string; } // 自定义实体示例 interface ISomeEntity extends IBaseEntity { firstName: string; lastName: string; middle: string; }
该实现仅在传入单个额外排除属性时可正常运行:
// 正常通过类型校验 const e: OmittedEntity<ISomeEntity, "firstName"> = { lastName: "", middle: "", status: "" }
传入2个及以上属性组成的联合类型作为额外排除项时,会触发类型错误,无法同时排除所有传入属性:
// 抛出类型错误 const e: OmittedEntity<ISomeEntity, "firstName" | "lastName"> = { lastName: "", // 类型错误:不应存在该属性 firstName: "", // 类型错误:不应存在该属性 middle: "", status: "" }
预期实现效果为,传入多属性联合类型时可一次性排除所有对应属性,如下代码可正常通过校验:
const e: OmittedEntity<ISomeEntity, "firstName" | "lastName"> = { middle: "", status: "" }
修复方案
问题由TypeScript的分布式条件类型特性导致:条件类型中如果判断参数是未被包装的裸泛型参数,当传入联合类型时,TypeScript会将联合类型的每个成员单独代入条件逻辑运算,最终返回所有运算结果的联合类型,而非将整个联合类型作为整体处理。
只需给条件判断两侧的类型加上方括号,阻断分布式条件类型的分发逻辑即可,修正后的类型定义:
type OmittedEntity<TEntity extends IBaseEntity, TExtraOmissions extends (keyof TEntity) | void = void> = [TExtraOmissions] extends [keyof TEntity] ? Omit<TEntity, "id" | "collection" | TExtraOmissions> : Omit<TEntity, "id" | "collection">
修正后所有场景均可正常工作:
- 不传额外排除参数时,默认仅排除
id、collection两个固定属性 - 传入单个属性名时,在默认排除规则基础上额外排除指定属性
- 传入多属性联合类型时,可一次性排除所有传入的额外属性,预期代码可正常通过类型校验
内容的提问来源于stack exchange,提问作者Agrejus
相关产品推荐
相关产品推荐

