如何简化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
相关产品推荐
相关产品推荐

