TypeScript中类方法依构造函数选项实现条件返回类型
问题:根据构造函数选项切换类方法的返回类型
我确信这在TypeScript中可以实现,但找到的相关方案对我无效。
我需要实现一个类,其构造函数接收选项参数,让getData方法的返回类型根据multiple选项在string和string[]间切换:
(new MyClass({ multiple: true })).getData(); // 期望返回string[] (new MyClass({ multiple: false })).getData(); // 期望返回string
我尝试了两种方案,但都遇到相同的类型错误:
方案1:将整个选项对象设为泛型
type Options = { multiple: boolean; } class MyClass<O extends Options> { constructor(private options: O) {} public getData = (): O["multiple"] extends true ? string[] : string => { if (this.options.multiple) { return ["foo", "bar"] as string[]; } return "foo" as string; }; }
报错信息:TS2322: Type 'string[]' is not assignable to type 'O["multiple"] extends true ? string[] : string'
方案2:仅将multiple字段设为泛型
class Day<TReturnsArray extends boolean> { constructor(private options: { multiple: TReturnsArray }) {} public getData = (): TReturnsArray extends true ? string[] : string => { if (this.options.multiple) { return ["foo", "bar"] as string[]; } return "foo" as string; }; }
同样触发上述错误,我不清楚为什么string[]无法匹配这个条件返回类型,错误信息也没有进一步的说明。
解决方案
问题根源在于TypeScript无法在条件分支中自动推断泛型条件类型的具体分支。以下是几种可行的解决方式:
方法1:精准类型断言
在每个返回分支中,将值断言为对应分支的条件类型,明确告诉TypeScript当前返回值符合该分支的类型要求:
class MyClass<TReturnsArray extends boolean> { constructor(private options: { multiple: TReturnsArray }) {} public getData(): TReturnsArray extends true ? string[] : string { if (this.options.multiple) { return ["foo", "bar"] as TReturnsArray extends true ? string[] : never; } else { return "foo" as TReturnsArray extends true ? never : string; } } }
方法2:使用函数重载
通过给构造函数和getData方法定义重载签名,让TypeScript直接根据传入的选项参数推断返回类型,这种方式不需要泛型,代码更直观:
class MyClass { private readonly multiple: boolean; // 构造函数重载 constructor(options: { multiple: true }); constructor(options: { multiple: false }); constructor(options: { multiple: boolean }) { this.multiple = options.multiple; } // getData方法重载 getData(): string[]; getData(): string; getData(): string | string[] { if (this.multiple) { return ["foo", "bar"]; } return "foo"; } } // 测试验证 const multiInstance = new MyClass({ multiple: true }); const multiResult = multiInstance.getData(); // 类型自动推断为string[] const singleInstance = new MyClass({ multiple: false }); const singleResult = singleInstance.getData(); // 类型自动推断为string
方法3:自定义类型守卫
通过自定义类型守卫函数,帮助TypeScript在条件分支中缩小实例的泛型类型范围:
class MyClass<TReturnsArray extends boolean> { constructor(private readonly options: { multiple: TReturnsArray }) {} // 自定义类型守卫,判断当前实例是否为multiple=true的情况 private isMultiple(): this is MyClass<true> { return this.options.multiple; } public getData(): TReturnsArray extends true ? string[] : string { if (this.isMultiple()) { return ["foo", "bar"]; // TypeScript now knows this branch returns string[] } else { return "foo"; // TypeScript now knows this branch returns string } } }
内容的提问来源于stack exchange,提问作者Lesik2008
相关产品推荐
相关产品推荐

