TypeScript:如何使方法返回类型与输入类型一致并解决推导问题
解决TypeScript中方法返回类型与输入一致及代码冗余问题
针对你遇到的两个问题——返回类型无法精确推导、代码重复,我们可以通过泛型和动态构造实例的方式来完美解决,下面一步步拆解方案:
1. 用泛型让返回类型与输入精确匹配
你原来的方法返回类型是Point | Vector,TypeScript无法根据传入的具体类型自动缩小返回范围。通过给方法添加泛型参数,我们可以捕获输入参数的具体类型,让返回类型和输入完全一致:
// 先定义基础的Point和Vector类 class Point { constructor(public x: number, public y: number, public z: number) {} } class Vector { constructor(public x: number, public y: number, public z: number) {} } // 假设sum方法属于某个拥有x/y/z属性的类(比如基类或工具类) class BaseXYZ { constructor(public x: number, public y: number, public z: number) {} // 泛型T约束为Point或Vector,输入o为T类型,返回T类型 sum<T extends Point | Vector>(o: T): T { // 获取输入对象的构造函数,断言为能接收三个number参数的构造器 const Constructor = o.constructor as new (x: number, y: number, z: number) => T; // 动态创建对应类型的实例,避免重复代码 return new Constructor(o.x + this.x, o.y + this.y, o.z + this.z); } } // 让Point和Vector继承BaseXYZ,这样它们就拥有sum方法 class Point extends BaseXYZ {} class Vector extends BaseXYZ {}
这样调用时,TypeScript会自动推导返回类型:
const point1 = new Point(1, 2, 3); const pointResult = point1.sum(new Point(4, 5, 6)); // pointResult的类型是Point,而非Point | Vector const vector1 = new Vector(1, 2, 3); const vectorResult = vector1.sum(new Vector(4, 5, 6)); // vectorResult的类型是Vector,而非Point | Vector
2. 消除代码冗余
原来的写法中,判断instanceof后重复编写实例化逻辑,通过动态调用构造函数,我们只需要写一次实例化代码即可。核心思路是:输入对象的constructor属性指向它的类,我们可以直接用这个构造函数创建新实例,不用分别判断类型。
如果你的场景中不能用基类继承,比如Point和Vector是完全独立的类,也可以用这种方式改造sum方法:
class SomeClass { x: number; y: number; z: number; constructor(x: number, y: number, z: number) { this.x = x; this.y = y; this.z = z; } sum<T extends Point | Vector>(o: T): T { const Constructor = o.constructor as new (x: number, y: number, z: number) => T; return new Constructor(o.x + this.x, o.y + this.y, o.z + this.z); } }
额外的类型安全优化
为了让泛型约束更清晰,可以定义一个通用接口来描述Point和Vector的共同特征:
interface XYZType { x: number; y: number; z: number; constructor: new (x: number, y: number, z: number) => XYZType; } class Point implements XYZType { constructor(public x: number, public y: number, public z: number) {} } class Vector implements XYZType { constructor(public x: number, public y: number, public z: number) {} } // 此时泛型可以约束为XYZType,扩展性更好 sum<T extends XYZType>(o: T): T { const Constructor = o.constructor as new (x: number, y: number, z: number) => T; return new Constructor(o.x + this.x, o.y + this.y, o.z + this.z); }
这样后续如果新增类似的类(比如Line),只要实现XYZType接口,就能直接复用sum方法,不需要修改泛型约束。
内容的提问来源于stack exchange,提问作者RangedNeedles
相关产品推荐
相关产品推荐

