如何根据Class类型参数确定TypeScript函数的返回类型?
解决TypeScript中基于类实例参数的返回类型推断问题
你的问题根源在于TypeScript的结构类型系统:空类Foo和Bar的实例结构完全一致(都没有任何属性/方法),所以TypeScript会将它们视为可兼容的类型,导致你的条件类型和重载写法都无法正确区分两者。
下面是几种可行的解决方案:
方案1:给类添加标志性属性(最直观)
通过给每个类添加唯一的字面量属性,让TypeScript能通过结构区分它们:
class Foo { readonly type: 'Foo' = 'Foo' } class Bar { readonly type: 'Bar' = 'Bar' } function update<T extends Foo | Bar>(item: T): T['type'] { return item.type as T['type'] } // 测试 const foo = new Foo() const bar = new Bar() const result1 = update(foo) // 类型:"Foo" const result2 = update(bar) // 类型:"Bar"
方案2:利用私有属性实现名义类型
如果不想暴露额外属性,可以用私有属性让TypeScript将两个类视为不同类型(私有属性的兼容性检查基于类本身而非结构):
class Foo { private readonly _brand: void } class Bar { private readonly _brand: void } function update<T extends Foo | Bar>(item: T): T extends Foo ? 'Foo' : 'Bar' { return (item instanceof Foo ? 'Foo' : 'Bar') as T extends Foo ? 'Foo' : 'Bar' } // 测试 const foo = new Foo() const bar = new Bar() const result1 = update(foo) // 类型:"Foo" const result2 = update(bar) // 类型:"Bar"
方案3:正确编写重载并配合类型收窄
如果坚持使用重载,需要在函数体内通过instanceof做类型收窄,同时确保TypeScript能正确匹配重载分支:
class Foo {} class Bar {} function update(item: Foo): 'Foo'; function update(item: Bar): 'Bar'; function update(item: Foo | Bar): 'Foo' | 'Bar' { if (item instanceof Foo) { return 'Foo' as const } return 'Bar' as const } // 测试 const foo = new Foo() const bar = new Bar() const result1 = update(foo) // 类型:"Foo" const result2 = update(bar) // 类型:"Bar"
这里的关键是用instanceof基于原型链判断实例类型,同时返回字面量类型(as const确保返回值是具体的字符串字面量而非string),让TypeScript能正确关联重载的参数和返回类型。
内容的提问来源于stack exchange,提问作者WW00WW
相关产品推荐
相关产品推荐

