TypeScript augmentation of PlayCanvas classes

Hi guys,

I could use some help on a project built on your TypeScript template found here:

https://github.com/playcanvas/playcanvas-editor-ts-template

I’m fairly new to TypeScript and not proficient in its inner workings with tsconfig.json and whatnot. But from what I can gather, the template is set up to not use WebPack to transpile to a singular main.build.js as others are. That asset gets uploaded to PlayCanvas via playcanvas-sync. This all works great and with minimal setup.

For some reason, though, it seems I cannot use the typical modular workflow and have to rely on namespaces instead, which I believe might be an older way of working in TypeScript. That’s okay, but I can’t figure out how to augment existing PlayCanvas classes without it transpiling in a manner which PlayCanvas can’t parse.

With the following, I get no errors in Visual Studio Code and it IntelliSenses correctly, but PlayCanvas gives me an Uncaught ReferenceError: define is not defined.

export { }

declare global {
    namespace pc {
        interface AppBase {
            getTimeMs(): number,
            getTimeSec(): number,
        }

        interface Quat {
            angle(rhs: Quat): number,
            dot(rhs: Quat): number,
        }
    }
}

pc.AppBase.prototype.getTimeMs = function (): number {
    // @ts-ignore
    return this._time;
}

pc.AppBase.prototype.getTimeSec = function (): number {
    // @ts-ignore
    return this._time * 1000;
}

pc.Quat.prototype.angle = function (rhs: pc.Quat): number {
    const f = this.dot(rhs);
    return Math.acos(Math.min(Math.abs(f), 1)) * 2 * 57.29578;
}

pc.Quat.prototype.dot = function (rhs: pc.Quat): number {
    return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z + this.w * rhs.w;
}

As you can see, I’m trying to add some methods to the AppBase and Quat classes. I hope you guys have ideas how to get it working in both VSC and PlayCanvas. :smiley:

I figured it out! :open_mouth: Persistence is key, boys and girls… And a lot of Stack Overflow

Extensions.ts file somewhere in the src folder:

// Module name is irrelevant
declare module 'Extensions' {
    global {
        namespace pc {
            interface AppBase {
                getTimeMs(): number;
                getTimeSec(): number;
            }

            interface Quat {
                angle(rhs: Quat): number;
                dot(rhs: Quat): number;
            }
        }
    }
}

pc.AppBase.prototype.getTimeMs = function (): number {
    // @ts-ignore
    return this._time;
}

pc.AppBase.prototype.getTimeSec = function (): number {
    // @ts-ignore
    return this._time * 1000;
}

pc.Quat.prototype.angle = function (rhs: pc.Quat): number {
    const f = this.dot(rhs);
    return Math.acos(Math.min(Math.abs(f), 1)) * 2 * 57.29578;
}

pc.Quat.prototype.dot = function (rhs: pc.Quat): number {
    return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z + this.w * rhs.w;
}

Now don’t ask me why this works, but it does in my case! IntelliSense and no errors in VSC or PlayCanvas. Hooray!

2 Likes

Thanks for posting the solution!