如何让TypeScript分布式联合类型兼容类方法中的this?
问题解决:分布式联合类型兼容类方法this与普通对象
原问题与代码
实现了分布式联合类型UnionKeys、ValueOfUnion,以及类型安全访问函数dig,普通对象(含联合类型)调用正常,但类方法中传入this调用dig时类型推断失效。
原类型定义
type UnionKeys<T> = T extends T ? keyof T : never; type ValueOfUnion<T, K extends UnionKeys<T>> = T extends infer U ? K extends keyof U ? T[K] : undefined : never;
原dig函数
function dig<T, K extends UnionKeys<T>>( obj: T, key: K, ): ValueOfUnion<T, K> { return obj[key as keyof T] as any; }
正常使用示例(普通对象)
type FooBar = {foo: string} | {bar: string}; const fooBar = {foo: 'foo'} as FooBar; dig(fooBar, 'foo'); // 类型推断正确,返回string | undefined
失效示例(类方法)
class FooBarHolder { public fooBar: FooBar; public doSomething() { const fooBar = dig(this, 'fooBar') // 类型推断报错,无法匹配泛型约束 } }
问题原因
原dig函数的泛型约束K extends UnionKeys<T>属于循环依赖约束:K的范围依赖T的类型,而T的推断又依赖K的传入值。当传入类的this(具体非联合类型)时,TypeScript无法完成正确的泛型推断,导致类型校验失败。
解决方案
调整泛型约束与返回类型逻辑,去掉循环依赖,同时保留对联合类型和普通对象的支持:
优化后的类型与函数
// 保留UnionKeys用于提取联合类型的所有键 type UnionKeys<T> = T extends unknown ? keyof T : never; // 重新设计值类型提取逻辑,支持分布式处理 type ValueAtKey<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : undefined : never; // 调整泛型约束,先推断T,再约束K为UnionKeys<T> function dig<T, K extends UnionKeys<T>>( obj: T, key: K ): ValueAtKey<T, K> { return obj[key as keyof T] as any; }
简化版实现(更简洁)
如果不需要单独暴露UnionKeys和ValueAtKey,可以直接整合到函数的重载中:
function dig<T, K extends PropertyKey>( obj: T, key: K ): T extends unknown ? K extends keyof T ? T[K] : undefined : never; function dig<T, K extends PropertyKey>(obj: T, key: K) { return obj[key as keyof T] as any; }
验证类方法调用
调整后,类方法中的调用可以正常推断类型:
class FooBarHolder { public fooBar: FooBar; public doSomething() { const fooBar = dig(this, 'fooBar'); // 类型推断为FooBar,正确 } }
原理说明
- 使用
T extends unknown触发分布式条件类型,自动遍历联合类型的每个成员进行类型判断; - 泛型约束改为先推断
T,再让K匹配UnionKeys<T>(或直接用PropertyKey配合返回类型的条件判断),避免循环依赖; - 返回类型通过条件类型分别处理:对于联合类型成员,判断键是否存在并返回对应类型或
undefined;对于非联合类型(如类的this),直接返回对应属性类型。
内容的提问来源于stack exchange,提问作者Alec
相关产品推荐
相关产品推荐

