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

如何实现泛型接口实现类的类型安全使用?

解决方案

要实现你需要的类型安全,核心是让工厂函数的返回类型与输入参数强关联,同时保留每个实现类的泛型约束。可以通过泛型映射来达成目标:

1. 定义类型映射

先创建一个类型,把输入的数字和对应的具体服务类绑定,让TS能明确参数和返回值的对应关系:

type ServiceMap = {
  1: ConcreteOne;
  2: ConcreteTwo;
};

2. 改造工厂函数为泛型函数

让getConcrete接收泛型参数,对应输入的数字类型,返回映射中对应的服务类:

function getConcrete<T extends keyof ServiceMap>(number: T): ServiceMap[T] {
  if(number === 1) {
    return new ConcreteOne() as ServiceMap[T];
  }
  if(number === 2) {
    return new ConcreteTwo() as ServiceMap[T];
  }
  throw new Error("Invalid service number");
}

这里的类型断言是安全的——我们明确知道分支返回值和泛型的对应关系,TS只是无法自动推断这一点。

3. 验证类型安全效果

现在主逻辑里的类型会自动关联,同时跨实例传参的错误会被TS捕获:

// 正确用法:同一实例传参,无类型错误
function mainFunction(number: 1 | 2) {
  const concrete = getConcrete(number);
  const data = concrete.getData();
  concrete.useData(data);
}

// 错误用法:跨实例传参触发类型错误
function crossInstanceTest() {
  const concrete1 = getConcrete(1);
  const concrete2 = getConcrete(2);
  const data = concrete1.getData();
  concrete2.useData(data); // TS错误:类型"{ foo: string; }"的参数不能赋给类型"{ foo: number; }"的参数
}

方案优势

  • 工厂函数的返回类型不再是模糊的联合类型,而是和输入参数一一对应的具体类型,TS能完整跟踪每个实例的真实类型。
  • 同一实例的getData()返回值和useData()参数类型完全匹配,保证类型安全。
  • 不同实例之间的类型天然不兼容,跨实例传参时会直接触发类型错误,符合你的需求。

完整代码示例

interface GenericService<Data extends {}> {
  getData(): Data;
  useData(data: Data): Data;
}

class ConcreteOne implements GenericService<{ foo: string }> {
  getData() {
    return { foo: 'bar' };
  }

  useData(data: { foo: string }): { foo: string } {
    return data;
  }
}

class ConcreteTwo implements GenericService<{ foo: number }> {
  getData() {
    return { foo: 1 };
  }

  useData(data: { foo: number }): { foo: number } {
    return data;
  }
}

type ServiceMap = {
  1: ConcreteOne;
  2: ConcreteTwo;
};

function getConcrete<T extends keyof ServiceMap>(number: T): ServiceMap[T] {
  if(number === 1) {
    return new ConcreteOne() as ServiceMap[T];
  }
  if(number === 2) {
    return new ConcreteTwo() as ServiceMap[T];
  }
  throw new Error("Invalid service number");
}

// 正确用法示例
function mainFunction(number: 1 | 2) {
  const concrete = getConcrete(number);
  const data = concrete.getData();
  concrete.useData(data);
}

// 错误用法示例(触发类型错误)
function crossInstanceTest() {
  const concrete1 = getConcrete(1);
  const concrete2 = getConcrete(2);
  const data = concrete1.getData();
  concrete2.useData(data);
}

内容的提问来源于stack exchange,提问作者Jack Butler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:48:20