TypeScript泛型类与联合类型的类型守卫问题
泛型类类型守卫无法缩小联合类型的问题分析与解决
问题根源
你的hasStat方法没有定义正确的类型谓词,TypeScript无法从方法的布尔返回值推断出泛型类的类型参数T的具体结构,自然无法将联合类型的实例缩小到目标子类型。默认情况下,普通的布尔返回函数不会触发类型缩小,尤其是涉及泛型联合类型时,TypeScript需要明确的类型断言来关联运行时检查和编译时类型。
解决方法
修改hasStat方法,添加基于泛型的类型谓词,利用Extract工具类型从联合类型中筛选出包含指定属性的分支。具体来说,类型谓词需要断言当前实例属于联合类型中符合Attributes<Record<K, Attribute>>的子类型。
修正后的代码示例
type Attribute = { value: number }; class Attributes<T extends Record<string, Attribute> = {}> { private stats: T = {} as T; // 修正后的hasStat,添加类型谓词 hasStat<K extends string>(key: K): this is Extract<this, Attributes<Record<K, Attribute>>> { return key in this.stats; } getStat<K extends keyof T>(key: K): T[K] { return this.stats[key]; } } // 使用示例 const attr: Attributes<{ foo: Attribute }> | Attributes<{ bar: Attribute }> = Math.random() > 0.5 ? new Attributes<{ foo: Attribute }>() : new Attributes<{ bar: Attribute }>(); if (attr.hasStat('foo')) { // 此时attr已被正确缩小为Attributes<{ foo: Attribute }> const fooAttr = attr.getStat('foo'); // 无报错 console.log(fooAttr.value); }
关键细节说明
Extract<this, Attributes<Record<K, Attribute>>>:Extract会从this的联合类型中提取出与Attributes<Record<K, Attribute>>兼容的子类型。当你调用hasStat('foo')时,TypeScript会自动推断K为'foo',进而筛选出Attributes<{ foo: Attribute }>分支。- 泛型约束
T extends Record<string, Attribute>:确保T始终是属性为Attribute的对象类型,避免类型谓词出现歧义。
内容的提问来源于stack exchange,提问作者stambolievv
相关产品推荐
相关产品推荐

