TypeScript如何实现兼容泛型类的cast类型转换函数
问题原因
TS的泛型是编译期擦除的,不存在运行时表示。你写的C<string>属于类型层面的写法,不能作为值传入函数参数位置——作为值存在的C是泛型类的构造函数,本身不接受类型参数传参,所以会抛出ts(2635)错误。
改造方案
核心思路是把泛型参数的指定从「传入构造函数的位置」移动到「cast函数的泛型参数位置」,值层面始终传入原始构造函数用于instanceof运行时校验,泛型参数只在类型层面控制返回值类型,同时保留非泛型类的自动推导能力。
改造后的cast函数
type AnyConstructor = new (...args: any[]) => any; export function cast<T>(obj: any, klass: AnyConstructor): T; export function cast<T extends AnyConstructor>(obj: any, klass: T): InstanceType<T>; export function cast(obj: any, klass: AnyConstructor) { if (!(obj instanceof klass)) { throw new Error(`Not an instance of ${klass.name}: ${obj.constructor.name}`); } return obj; }
使用方式
- 普通非泛型类和原有写法完全兼容,无需改动,TS会自动推导返回类型:
interface I {} class C implements I {} const i: I = {} as I; // 自动推导c的类型为C const c = cast(i, C);
- 泛型类场景下,手动给cast传入目标泛型类型,值参数位置只传原始类构造函数,不要给类加
<T>后缀:
interface I<T> {} class C<T> implements I<T> {} const i: I<string> = {} as I<string>; // 手动指定返回类型为C<string>,c的类型符合预期,编译正常通过 const c = cast<C<string>>(i, C);
说明
该方案完全通用,不绑定任何特定类型层级:运行时的instanceof校验逻辑和原函数完全一致,仅在类型层面支持传入任意泛型类的实例类型作为返回值类型,符合不需要校验泛型参数内部属性、只要通过编译的要求,不需要额外使用as类型断言。
内容的提问来源于stack exchange,提问作者kberg
相关产品推荐
相关产品推荐

