RangedNeedles
RangedNeedles

Reputation: 80

TypeScript - Define return type as input type

So, to simplify things, suppose I've got a method as follows

sum(o: Point | Vector): Point | Vector {
  if (o instanceof Point) {
    return new Point(o.x + this.x, o.y + this.y, o.z + this.z)
  }
  if (o instanceof Vector) {
    return new Vector(o.x + this.x, o.y + this.y, o.z + this.z)
  }
}

As you can see, the actual logic is the exact same thing which makes it a bit silly to have to duplicate it. When invoking the method and passing it, for example, a Point object, the return type is not correctly derived. I have to do an explicit cast to Point.

I could use generic typing and declare the parameter as T but then it won't recognize the x, y and z variables of course.

My questions is a bit like this one but with the difference my types are not arrays and that the question doesn't have an answer.

Can this be solved somewhat more beautifully in TypeScript?

Upvotes: 1

Views: 513

Answers (2)

Lajos Gallay
Lajos Gallay

Reputation: 1317

I think you should use a generic type with a restriction, like:

export abstract class SumableClass {

    public sum<T extends SumableClass >(o: T): T {
        return o.constructor(o.x + this.x, o.y + this.y, o.z + this.z);
    }

    constructor(public x: number, public y: number, public z: number) {

    }
}

Also defined an abstract (SumableClass), Point and Vector should inherited from it

Upvotes: 0

ekim boran
ekim boran

Reputation: 1819

You can pass the constructor with generic constraint explicitly.

function sum<T extends Point | Vector>(c: new (a: number, b: number,c: number) => T, o: T): (T) {  
  return new c(o.x + this.x, o.y +  this.y, o.z + this.z); 
}

let t = x.sum(Point, new Point(1, 2, 3));

Upvotes: 2

Related Questions