如何让TypeScript自动推断泛型关联的具体类型参数?
我定义了基接口IInferredTypeBase及其子接口IInferredType(该层级下实际存在多个子类接口),同时定义了针对该层级的泛型接口IGenericForInferredType<T extends IInferredTypeBase>。
我希望TypeScript能在以下场景中自动推断泛型参数:
type ICallback<TInferredType extends IInferredTypeBase, TGenericForInferredType extends IGenericForInferredType<TInferredType>> = (instance: TInferredType) => any; function register< TInferredType extends IInferredTypeBase, TGenericForInferredType extends IGenericForInferredType<TInferredType> >( param1: new () => TGenericForInferredType, callback: ICallback<TInferredType, TGenericForInferredType> ) { // ... }
register函数接收两个参数:param1是实现IGenericForInferredType<TInferredType>的类构造函数,我期望以此自动推断callback的参数类型为TInferredType,但目前并未生效。
举个具体例子:
class ClassImplementingGenericForInferredType implements IGenericForInferredType<IInferredType> { }
调用register(ClassImplementingGenericForInferredType, (instance) => {})时,instance的类型被推断为基接口IInferredTypeBase,而非预期的IInferredType。
我的需求是无需手动指定IInferredType,让TypeScript自动推断出该类型。此外,这些类型均由C#生成,我不想重复编写其层级和泛型关联关系。
问题核心在于TypeScript无法从IGenericForInferredType<TInferredType>的实现类中反向追踪出具体的TInferredType,原泛型约束仅限定了类型关系,未强制TypeScript提取泛型参数的具体类型。
可以通过条件类型推断解决,步骤如下:
- 定义工具类型,从
IGenericForInferredType的实现中提取泛型参数:
type ExtractInferredType<T extends IGenericForInferredType<any>> = T extends IGenericForInferredType<infer U> ? U : never;
- 修改
register函数的泛型定义,仅保留TGenericForInferredType作为泛型参数,通过工具类型自动推导TInferredType:
type ICallback<TInferredType extends IInferredTypeBase> = (instance: TInferredType) => any; function register<TGenericForInferredType extends IGenericForInferredType<any>>( param1: new () => TGenericForInferredType, callback: ICallback<ExtractInferredType<TGenericForInferredType>> ) { // ... }
修改后调用register(ClassImplementingGenericForInferredType, (instance) => {}),instance会被自动推断为IInferredType,完全符合预期,且无需手动指定泛型参数。
原理是利用TypeScript的infer关键字,从TGenericForInferredType中反向提取它实现IGenericForInferredType时使用的具体泛型参数,让TypeScript自动推导回调函数的参数类型。
内容的提问来源于stack exchange,提问作者nvirth

