TypeScript松散泛型Mixin出现类型丢失问题的技术问询
TypeScript Mixin类型丢失问题解决
基础示例代码
import { Observable, of } from 'rxjs'; class Service<TDataType> { public foo(f: TDataType): Observable<TDataType> { return of(f); } } type GConstructor<T = {}> = new (...args: any[]) => T; type ServiceConstructible<TDataType> = GConstructor<Service<TDataType>>; function applyBarMixin<TDataType, TBase extends ServiceConstructible<TDataType>>(Base: TBase) { return class BarService extends Base{ public bar(b: TDataType): Observable<TDataType> { return of(b); } }; }
问题现象
应用Mixin后,bar()方法的参数和返回类型丢失,变为unknown:
const FooBar = applyBarMixin(Service<number>); const service = new FooBar(); let x = service.bar(1); // x: unknown
原因分析
问题出在泛型参数推断逻辑上:当传入Service<number>作为Base时,TypeScript无法自动将TDataType推断为number。ServiceConstructible<TDataType>仅定义了构造函数的类型约束,但TypeScript无法从传入的构造函数反向推导其实例的泛型参数,最终导致TDataType被默认推断为unknown,进而让bar方法的类型全部失效。
解决方案
调整applyBarMixin的泛型定义,让TDataType从传入的Base构造函数的实例类型中自动提取,而非作为独立泛型参数。
方案1:通过infer自动提取泛型参数
import { Observable, of } from 'rxjs'; class Service<TDataType> { public foo(f: TDataType): Observable<TDataType> { return of(f); } } type GConstructor<T = {}> = new (...args: any[]) => T; // 从Service实例类型中提取泛型参数 type ExtractServiceDataType<T> = T extends Service<infer U> ? U : never; function applyBarMixin<TBase extends GConstructor<Service<any>>>(Base: TBase) { // 自动推断目标类型 type TDataType = ExtractServiceDataType<InstanceType<TBase>>; return class BarService extends Base { public bar(b: TDataType): Observable<TDataType> { return of(b); } }; }
方案2:调用时显式指定泛型参数
若不想修改Mixin函数,也可以在调用时直接指定泛型参数:
const FooBar = applyBarMixin<number, typeof Service<number>>(Service<number>); const service = new FooBar(); let x = service.bar(1); // x: Observable<number>
验证效果
使用方案1后,类型推断恢复正常:
const FooBar = applyBarMixin(Service<number>); const service = new FooBar(); let x = service.bar(1); // x: Observable<number> service.bar('string'); // 触发类型错误,符合预期
内容的提问来源于stack exchange,提问作者Hafnernuss
相关产品推荐
相关产品推荐

