如何根据对象布尔属性值缩小函数属性的返回类型?
实现关联类型的可行方案
你的需求完全可以实现,问题出在之前的写法没能让TypeScript把x的取值和f的返回类型做精准关联。下面是两种有效的实现方式:
方案1:使用可区分联合类型
这是最直观的方式,通过联合两个明确的类型分支,让x的字面量作为区分标志,TypeScript能自动根据x的值推断f的返回类型:
type IA<T> = | { x: true; f: () => T } | { x: false; f: () => number }; // 正常赋值,无类型错误 const x0: IA<string> = { f: () => "hello", x: true as const }; // 类型守卫完全生效 if (x0.x === true) { x0.f().toUpperCase(); // 确定是string类型,调用方法没问题 } else { x0.f().toFixed(); // 确定是number类型,调用方法没问题 }
方案2:带布尔泛型参数的接口
如果偏好接口形式,可以新增一个泛型参数约束x的类型,通过条件类型绑定f的返回值:
interface IA<T, X extends boolean = boolean> { x: X; f: () => X extends true ? T : number; } // 指定X为true,赋值时类型匹配 const x0: IA<string, true> = { f: () => "hello", x: true }; // 类型判断正常工作 if (x0.x === true) { x0.f().toUpperCase(); } else { // 因为X固定为true,TypeScript会提示此分支不可达 x0.f().toFixed(); } // 动态场景下,TypeScript也能自动推断分支类型 const x1 = Math.random() > 0.5 ? ({ x: true, f: () => "hi" } as IA<string>) : ({ x: false, f: () => 123 } as IA<string>); if (x1.x === true) { x1.f().toUpperCase(); } else { x1.f().toFixed(); }
原写法失效的原因
你之前用this['x'] extends true ? T : number作为返回值,但IA<T>中的x是boolean类型(不是true/false字面量),TypeScript无法在接口层面确定this.x的具体取值,只能推断f的返回类型是T | number,导致赋值时出现类型不匹配的错误。而上面两种方案要么通过联合类型明确区分两种状态,要么用泛型参数固定x的字面量类型,让TypeScript能精准关联类型。
内容的提问来源于stack exchange,提问作者Ian Warburton
相关产品推荐
相关产品推荐

