如何为方法定义类型,使其返回原始值或传入类的实例?
解决泛型类返回值类型推导问题
我来帮你搞定这个问题!咱们先拆解下原代码里的核心问题,再一步步修正:
问题根源
你的代码里有两个关键问题导致类型推导不符合预期:
ctor<T>的定义混淆了构造函数类型和实例类型,导致传入自定义类(比如Matrix)时,泛型T被错误推导为typeof Matrix(构造函数类型),而非Matrix(实例类型)。returnPrimitive的逻辑虽然方向正确,但和ctor的类型关联后,没有正确绑定实例类型到原始类型的映射。
修正方案
下面是调整后的完整代码,我会逐段解释:
// 第一步:修正原始类型映射逻辑,基于实例类型判断返回值 type ReturnPrimitive<T> = T extends Number ? number : T extends String ? string : T extends Boolean ? boolean : T; // 第二步:明确构造函数类型,它负责生成T类型的实例 type Ctor<T> = new (...args: any[]) => T; class Foo<T> { private Type: Ctor<T>; constructor(Type: Ctor<T>) { this.Type = Type; } getValue(val: any): ReturnPrimitive<T> { const instance = new this.Type(val); // 运行时判断:如果是原始包装类实例,返回原始值;否则返回实例本身 if (instance instanceof Number || instance instanceof String || instance instanceof Boolean) { return instance.valueOf() as ReturnPrimitive<T>; } return instance as ReturnPrimitive<T>; } }
测试验证
现在咱们测试两种场景,类型推导完全符合预期:
class Matrix {} // 场景1:传入Number包装类,返回number类型 const numFoo = new Foo(Number); const numVal = numFoo.getValue(123); // numVal: number // 场景2:传入自定义类,返回Matrix实例类型 const matrixFoo = new Foo(Matrix); const matrixVal = matrixFoo.getValue(); // matrixVal: Matrix
关键调整说明
Ctor<T>的修正:明确表示这是一个能生成T类型实例的构造函数,TypeScript会自动把传入的构造函数(比如Matrix)映射到它的实例类型Matrix,而非构造函数本身的类型。ReturnPrimitive<T>的修正:基于实例类型T做判断,清晰区分原始包装类实例和自定义类实例的返回值类型。- 运行时逻辑:通过
instanceof判断是否为原始包装类实例,调用valueOf()获取原始值;自定义类则直接返回实例,配合类型断言让TypeScript认可返回值的类型。
可选:更严谨的类型约束
如果想让类型检查更严格,可以给原始包装类的构造函数加上专属约束,确保它们都有正确的valueOf方法:
// 定义原始包装类的构造函数类型,绑定实例和原始值的关系 type PrimitiveWrapperCtor<TInstance, TPrimitive> = new (...args: any[]) => TInstance & { valueOf(): TPrimitive }; // 联合所有原始包装类构造函数 type PrimitiveCtors = PrimitiveWrapperCtor<Number, number> | PrimitiveWrapperCtor<String, string> | PrimitiveWrapperCtor<Boolean, boolean>; class Foo<T> { private Type: Ctor<T>; // 针对不同场景构造函数做更精确的类型约束 constructor(Type: T extends Number ? PrimitiveWrapperCtor<Number, number> : T extends String ? PrimitiveWrapperCtor<String, string> : T extends Boolean ? PrimitiveWrapperCtor<Boolean, boolean> : Ctor<T> ) { this.Type = Type; } getValue(val: any): ReturnPrimitive<T> { const instance = new this.Type(val); if ('valueOf' in instance && (instance instanceof Number || instance instanceof String || instance instanceof Boolean)) { return instance.valueOf() as ReturnPrimitive<T>; } return instance as ReturnPrimitive<T>; } }
内容的提问来源于stack exchange,提问作者Fuzzyma
相关产品推荐
相关产品推荐

