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

如何简化TypeScript抽象类子类中的复杂泛型类型声明

简化TypeScript抽象类子类的类型声明

方案1:利用this类型与内置工具类型自动推断

直接在抽象类的convertToAppData方法中,通过Parameters<this['interpreter']>[0]引用interpreter方法的参数类型,子类实现时无需手动声明复杂类型,TypeScript会自动根据子类的interpreter实现推断出参数类型。

// 抽象类定义
abstract class WeatherProcessor<Params, AppData> {
  abstract fetchData(params: Params): Promise<any>;
  abstract interpreter(data: any): AppData;

  async process(params: Params): Promise<AppData> {
    const rawData = await this.fetchData(params);
    return this.interpreter(rawData);
  }

  // 用Parameters工具类型+this引用简化类型
  abstract convertToAppData(data: Parameters<this['interpreter']>[0]): AppData;
}

// 子类实现
class CityWeatherProcessor extends WeatherProcessor<{ city: string }, { cityId: number }> {
  async fetchData(params: { city: string }): Promise<{ id: number; name: string }> {
    return Promise.resolve({ id: 123, name: params.city });
  }

  interpreter(data: { id: number; name: string }): { cityId: number } {
    return { cityId: data.id };
  }

  // 参数类型自动推断为{ id: number; name: string },无需手动指定
  convertToAppData(data) {
    return { cityId: data.id };
  }
}

方案2:添加原始数据泛型参数显式约束

给抽象类增加一个RawData泛型参数,用来明确指定接口返回的原始数据类型,所有依赖原始数据的方法直接复用该泛型,子类继承时一次性指定所有泛型参数,类型声明更清晰。

// 带RawData泛型的抽象类
abstract class WeatherProcessor<Params, RawData, AppData> {
  abstract fetchData(params: Params): Promise<RawData>;
  abstract interpreter(data: RawData): AppData;

  async process(params: Params): Promise<AppData> {
    const rawData = await this.fetchData(params);
    return this.interpreter(rawData);
  }

  // 直接使用RawData泛型作为参数类型
  abstract convertToAppData(data: RawData): AppData;
}

// 子类实现
class CityWeatherProcessor extends WeatherProcessor<
  { city: string },
  { id: number; name: string },
  { cityId: number }
> {
  async fetchData(params: { city: string }): Promise<{ id: number; name: string }> {
    return Promise.resolve({ id: 123, name: params.city });
  }

  interpreter(data: { id: number; name: string }): { cityId: number } {
    return { cityId: data.id };
  }

  // 参数类型自动匹配RawData泛型
  convertToAppData(data) {
    return { cityId: data.id };
  }
}

方案3:在抽象类中定义复用类型别名

在抽象类内部定义类型别名,引用interpreter方法的参数/返回类型,子类可直接继承这些别名,避免重复书写复杂类型。

// 定义UnWrap工具类型(如果需要)
type UnWrap<T> = T extends (...args: any[]) => infer R ? R : never;

abstract class WeatherProcessor<Params, AppData> {
  // 定义可复用的类型别名,子类自动继承
  protected type RawDataType = Parameters<this['interpreter']>[0];
  protected type AppDataType = ReturnType<this['interpreter']>;

  abstract fetchData(params: Params): Promise<RawDataType>;
  abstract interpreter(data: RawDataType): AppDataType;

  async process(params: Params): Promise<AppDataType> {
    const rawData = await this.fetchData(params);
    return this.interpreter(rawData);
  }

  abstract convertToAppData(data: RawDataType): AppDataType;
}

// 子类实现
class CityWeatherProcessor extends WeatherProcessor<{ city: string }, { cityId: number }> {
  async fetchData(params: { city: string }): Promise<{ id: number; name: string }> {
    return Promise.resolve({ id: 123, name: params.city });
  }

  interpreter(data: { id: number; name: string }): { cityId: number } {
    return { cityId: data.id };
  }

  // 直接使用继承的RawDataType类型别名
  convertToAppData(data: this['RawDataType']) {
    return { cityId: data.id };
  }
}

以上三种方案都能有效避免手动书写UnWrap<WeatherProcessor<...>['interpreter']>这类冗长类型,让子类实现更简洁。优先推荐方案1,无需额外泛型参数,完全依赖TypeScript的类型推断能力;如果需要更明确的类型约束,方案2是更好的选择。

内容的提问来源于stack exchange,提问作者Shihan Lu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:33:29