如何在带泛型的TypeScript类中用属性做类型守卫并确定条件类型?
解决方案:通过类型守卫关联泛型与运行时类型
问题核心在于TypeScript无法自动将类的泛型参数UN与实例属性useNumber的运行时检查关联,从而缩小input的类型。以下两种方案无需手动类型断言(as)即可解决:
方案一:自定义类型守卫函数
通过类方法定义类型守卫,明确泛型参数与运行时值的对应关系:
type X<T> = T extends true ? number : string; export class A<UN extends boolean, I = X<UN>> { useNumber: UN; constructor(useNumber: UN) { this.useNumber = useNumber; } a(input: string): string { return `${input}j`; } b(input: number): number { return input * 2; } // 自定义类型守卫:判断当前实例是否为数字类型分支 isNumberInstance(this: A<UN, I>): this is A<true, number> { return this.useNumber === true; } c(input: I): string { if (this.isNumberInstance()) { // TypeScript自动推断:input为number,可安全调用b方法 return this.b(input).toString(); } else { // TypeScript自动推断:input为string,可安全调用a方法 return this.a(input).toString(); } } } // 测试 const numInstance = new A(true); numInstance.c(123); // 正常执行 const strInstance = new A(false); strInstance.c("hello"); // 正常执行
关键细节:
- 调整泛型定义:将
I extends X<UN>改为I = X<UN>,确保I严格对应条件类型X<UN>,消除类型歧义。 - 类型守卫函数:
isNumberInstance通过this is A<true, number>告诉TypeScript,当useNumber为true时,当前实例的泛型参数UN固定为true,I固定为number;反之则对应false和string。
方案二:直接检查input类型
利用input的类型与useNumber的逻辑一致性,通过typeof直接缩小类型:
type X<T> = T extends true ? number : string; export class A<UN extends boolean, I = X<UN>> { useNumber: UN; constructor(useNumber: UN) { this.useNumber = useNumber; } a(input: string): string { return `${input}j`; } b(input: number): number { return input * 2; } c(input: I): string { if (typeof input === 'number') { return this.b(input).toString(); } else { return this.a(input).toString(); } } }
这种方式更简洁,因为input的类型I本身就是X<UN>的条件类型,与useNumber的逻辑完全匹配,TypeScript可直接通过typeof检查识别类型。
内容的提问来源于stack exchange,提问作者özüm
相关产品推荐
相关产品推荐

