You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中基于接口实现通用工厂方法的可行性问询

TypeScript接口实现通用get泛型方法的可行性问题

我有一组由OpenAPI Generator自动生成的TypeScript接口,希望实现如下示例的泛型方法:

interface Foo {}
function getFoo(id: string): Foo { /* ... */ }

interface Bar {}
function getBar(id: string): Bar { /* ... */ }

function get<T>(type: Type<T>, id: string): T {
    switch(type) {
        case typeof Foo:
            return getFoo(id);
        case typeof Bar:
            return getBar(id);
        default:
            throw "Unknown type";
    }
}

请问这种实现方式是否可行?

我尝试过两种方案,但都有问题:

  • 若Foo和Bar为类,可以用以下方式实现,但该方式不适用于接口:
    function get<T>(type: new() => T, id: string): T {
        switch(typeof new type()){
            // ...
        }
    }
    
  • 给接口添加标签,但这种方式无法避免get<Bar>('foo', id)这类类型不匹配的调用:
    interface Foo { type: 'foo'; }
    interface Bar { type: 'bar'; }
    
    function get<T>(type: string, id: string): T {
        switch(type) {
            case 'foo':
                return getFoo(id);
            case 'bar':
                return getBar(id);
            default:
                throw "Unknown type";
        }
    }
    

明确结论:原示例的实现方式不可行

TypeScript的接口是编译时专属类型,编译为JavaScript后会被完全擦除,不存在对应的运行时对象,因此typeof Foo这种写法本身就会报错——运行时根本没有Foo这个值,自然无法在switch语句中做判断。

可行的解决方案

方案1:类型映射+字面量约束,保障类型安全

通过定义类型映射表,约束类型标识与返回值类型的对应关系,从根源上避免类型不匹配的调用:

// 定义类型标识与接口的映射关系
type TypeMap = {
  foo: Foo;
  bar: Bar;
};

// 泛型方法:K必须是TypeMap的键,返回对应接口类型
function get<K extends keyof TypeMap>(type: K, id: string): TypeMap[K] {
  switch (type) {
    case 'foo':
      return getFoo(id) as TypeMap[K];
    case 'bar':
      return getBar(id) as TypeMap[K];
    default:
      throw new Error(`Unknown type: ${type}`);
  }
}

调用时,get('foo', id)会自动推导返回Foo类型,get('bar', id)返回Bar类型,编译器会直接拦截非强制转换的类型不匹配调用。

方案2:枚举作为类型标识,提升可读性

如果觉得字符串字面量不够直观,可以用枚举替代:

enum DataType {
  Foo = 'foo',
  Bar = 'bar'
}

// 关联枚举与接口的映射
type TypeMap = {
  [DataType.Foo]: Foo;
  [DataType.Bar]: Bar;
};

function get<K extends keyof TypeMap>(type: K, id: string): TypeMap[K] {
  switch (type) {
    case DataType.Foo:
      return getFoo(id) as TypeMap[K];
    case DataType.Bar:
      return getBar(id) as TypeMap[K];
    default:
      throw new Error(`Unknown type: ${type}`);
  }
}

调用时使用get(DataType.Foo, id),既能保证类型安全,代码可读性也更强。


内容的提问来源于stack exchange,提问作者Rasmus Faber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:31:03