如何实现仅含两种类型之一键的TypeScript泛型OnlyOne?
TypeScript 实现仅允许单一类型键的泛型 OnlyOne<T, U>
需求是构建泛型类型OnlyOne<T, U>,要求该类型的实例只能包含类型T的任意键组合,或者类型U的任意键组合,绝对不允许同时包含T和U的键。
示例定义:
type A = { name?: string; email?: string; }; type B = { x2?: number; phone?: string; }; type C = OnlyOne<A, B>;
期望效果:
// ✅ 允许:仅使用A的键 const res1: C = { name:'1' } // ✅ 允许:使用A的多个键 const res2: C = { name:'1', email:'email' } // ❌ 不允许:同时使用A和B的键 const res3: C = { name:'1', x2: 1 }
正确实现方式
type OnlyOne<T, U> = // 允许T的任意可选键,禁止U独有的键 (Partial<T> & Record<Exclude<keyof U, keyof T>, never>) | // 允许U的任意可选键,禁止T独有的键 (Partial<U> & Record<Exclude<keyof T, keyof U>, never>);
实现说明
Partial<T>:让T的所有键变为可选,支持任意子集组合(包括空对象)Record<Exclude<keyof U, keyof T>, never>:生成一个类型,其中所有U有但T没有的键被设为never,意味着这些键绝对不能出现在实例中- 用
|联合两种情况,确保实例只能属于其中一种场景,自然避免了混合T和U键的情况
原代码失效原因
你之前尝试的代码逻辑存在偏差:
type OnlyOne<T, U> = (T & U) extends infer O ? O extends T ? (Exclude<U, keyof T> & T) : O extends U ? (Exclude<T, keyof U> & U) : never : never;
T & U是同时包含T和U所有键的交叉类型,后续的O extends T或O extends U判断无法覆盖「T的子集」或「U的子集」的场景,本质上没有限制住混合键的情况,因此达不到需求。
内容的提问来源于stack exchange,提问作者MD10
相关产品推荐
相关产品推荐

