4

I am building a Typescript application, and I'm using an external js library (pixi.js for rendering). I have the .d.ts file and it's all working fine.

The file declares a class Point:

export class Point {

    x: number;
    y: number;

    constructor(x?: number, y?: number);

    clone(): Point;
    copy(p: Point): void;
    equals(p: Point): boolean;
    set(x?: number, y?: number): void;

}

I was wondering if there was any decent way to add functionality to this, or other, classes that are declared in a .d.ts file. For example, in this case, I could really use an add(), subtract(), negate() method and so on.

EDIT: To clarify, I do not want to extend this class by way of creating a subclass. I want to add functionality to the class itself. I don't want to have to deal with two classes (e.g. Point and PointEx) in my code - pixi uses Point internally and often returns it from functions, so I don't want the added overhead of casting Point to the extended object.

1 Answer 1

9

You can extend that class like with any other class:

class MyPoint extends Point {
    private name: string;

    constructor(name: string, x?: number, y?: number) {
        super(x, y);

        this.name = name;
    }

    public getName() {
        return this.name;
    }

    public add(other: Point): Point {
        return new Point(this.x + other.x, this.y + other.y);
    }
}

Edit

You can extend it using the prototype, like this:

interface Point {
    add(other: Point): Point;
}

Point.prototype.add = function(other: Point): Point {
    return new Point(this.x + other.x, this.y + other.y);
}

The first part (with the interface) is called Declaration Merging and it's when you add more definitions to exiting types.
The other part is the implementation of the function and adding it to the Point.prototype.

While this works, I would not recommend it:
The base Point is out of your control, what happens if tomorrow they change it and add their own add method which has a different signature than yours? You'll be forced to change your entire code base because of that.

What you can do with your own point class (which extends the base one) is to have a ctor from the base:

class MyPoint extends Point {
    constructor(base: Point) {
        super(base.x, base.y);

        // ...
    }
}

Or, add a factory method to the Point.prototype:

interface Point {
    toMyPoint(): MyPoint;
}

Point.prototype.toMyPoint = function(): MyPoint {
    return new MyPoint(this);
}

Both of these ways give you a convenient way of getting MyPoint out of a Point which you get as a result of some execution.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer! It's not what I am looking for however. I've clarified my position on the OP.
gotcha! check my revised answer
This is a great answer. If you don't mind me asking, how can I extend a class that is not exported? I would like to extend this Itiriri class to add a couple methods, but the library does not export it.
@Tobia you can't, you don't have direct access to it, looks like it was intentional, they only export the function, and want to keep the class as implementation detail. you can make a copy of that file in your source and use it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.