Ever considered TypeScript for PlayCanvas?


#1

I have spent quite a bit of time recently working with TypeScript and have come to the following conclusion:

  • It makes my code way more rigid and less random
  • IntelliSense is the best thing since sliced bread
  • It removes some of the mystique and feeling of wielding an enormous and chaotic power

So while the 3rd point is a bit of a con, the other 2 points very closely outweigh it. So with that I have decided to switch to TypeScript (at least for the time being). I have begun creating declarations for all the PlayCanvas engine code and will share it once I am done.

But here is the question to the community of PlayCanvas: Have you tried TypeScript? And if yes, what did you hate about it? I want to know so that I can bail out of this before I am in too deep.
Now a question to the creators of PlayCanvas: Have you considered creating the engine in TypeScript? Why not?


#2

TY Night7Sh4de for this solution. Every new idea or pattern is great to make this engine awesome… :slight_smile:


#3

Here is the gist of what I have so far. This is enough to get a coloured spinning cube using rigidbodies.


#4

We’ve taken the view that because, PlayCanvas is a library intended to be used in a wide-range of circumstances, making a tech-choice, like using a less common language, will limit people ability to choose PlayCanvas for their projects.

For that reason, we believe PlayCanvas should be and should remain written in “regular” javascript.

That said, I’m not sure whether it is possible to provide TypeScript bindings without heavily modifying the original engine?


#5

K well I can’t do it. Type safety is great and while the awesome power of VS is enticing, the near limitless (and limitlessly breakable) power of JavaScript is just not something I can pass up. I have updated the gist, it should be enough to make a simple game and isn’t particularly difficult to add to/improve. But being able to do stupid stuff like just giving an array a new object-like property or casually referencing properties found on the constructor of an object is just too amazing (and exceptionally hacky) to pass up. I gave TypeScript an honest try, but it was slowing me down even after I was working in a completely 100% TS context. Oh well.


#6

I put together a more complete one by using tsd-jsdoc.

https github.com/ncoder/engine/blob/feature/typescript/src/tsd-jsdoc/types.d.ts

The doc comments are good, but not complete or all applicable.

Also, tsd-jsdoc failed to convert some types. So some types are missing; possibly because of this bug, or simply because they don’t appear in the docs. I stubbed them out to get going.

Notable issues:
The enum types are probably wrong.
pc.events is defined as a module instead of an interface, and it’s used as a mixin, so that’s a problem.
There’s also function overrides taking ^2, ^3 and ^4 as suffixes. Those fail to compile, and i substituted with _. I’m not sure yet what the real answer is there.


#7

Typescript is a superset of javascript, there is virtualy no modification to be done. You’ll only need to generate a type description file, but even that is not require. The only thing would be the time to build the .js file but the compiler works really fast and it generate .js.map file for easy debugging.
There is to major benefit on top of my mind:

1: It would attract more developper since you can make an easy jump from javascript or c# to typescript.
2: It has no overhead or impact on current setup since “regular” javascript can be written alongside typescript in a .ts file and the ultimate result is still javascript (and well-generated readable javascript that is).

Please consider it, I know the javascript can heavily defended, but typescript is not a replacement, but rather a tool that can be used alongside.


#8

Correct me if I’m wrong, but I believe there are two options for supporting TypeScript:

  1. We hand-write a single playcanvas.d.ts which enforces type safety when calling the PlayCanvas API from TS-based applications. We update this playcanvas.d.ts file when we make changes to the public JS API.
  2. We rewrite the entire engine codebase as TS and then compile back to JS. This presumably auto-generates the playcanvas.d.ts file.

We could begin by doing 1. Personally, I’m open to this coming in the form of a PR from an open source contributor (@dave may or may not agree with me, especially since once it is merged, we become responsible for making sure the playcanvas.d.ts file remains in lock-step with the JS codebase).

Option 2 is a vast amount of work - the engine codebase is pretty large. We’ve managed just fine with JS rather than TS until now and there really isn’t much urgency to migrate to TS. If anything it might put developers off from contributing since far, far fewer devs know TS compared to JS.

Note that all this is only really relevant for non-Editor based applications since there’s no way to insert the TS compiler into the publishing process on the server at the moment.


#9

Could you use something like this? https://www.npmjs.com/package/tsd-jsdoc to convert the JSDoc to typings? I guess the JSDoc should remain accurate. Not sure how good that is, but it might be helpful.


#10

The fact that the first line is “Warning: Highly Experimental” makes me mildly nervous. :wink:


#11

I believe option 1 is the most interesting short-terms. There is a couple of tools that help building these files but an opensource contribution might be a good solution.
A type definition should be easy to maintain as long as the code base remain consistent, that too could be maintained by a few key contributor.
But even adding the compiler alone can be really useful, even just for game logic. we can still refer to the current documentation to makes calls.

For option 2 I understand it might not be feasible right now and not without a big incentive or advantage to do this migration. But in the future if you consider migrating, since, javascript is valid in typescript, all dependencies can remain as is, and only the public API can be changed at first.

As for the compiler it can be made to run client side in a single file (the file however is short of 300k). The compiler itself is written in typescript.

Managing scope and types with typescript withing the game code could prove really valuable for those who would want it.


#12

For me official support of a build system that includes ES6/7 features, NPM, source control, continuous integration etc is the primary thing I need and have to work around. I like TypeScript and have used it for a couple of projects, but it’s adoption isn’t particularly wide, the advantages of Async programming with ES7 features is super helpful.


#13

That’s the thing, I know typescript is not widely adopted, but it’s still the second most used web language after javascript.
But I do prefer typescript to javascript and I am positive that a lot of other programmer would be interested in building web app and games trough typescript. I come from a strong typed background, I’ve worked mainly with c#, java and c/c++ and I did try my hand at web programming but I never really got into it, on part because of the difference in the programming paradigm and environment of javascript and on other part because of the lack of viable solution to effectively build maintainable code without javascript. (I’ve tried Dart, most transpiler and a couple of _something_script). That until typescript, the sole reason I think it’s getting more and more adopted is that it enable people to bring their experience from more (I’d say “classic” from lack of a better word) language into the mix without compromising the codebase for current javascript programmer.
So it would really like it’s integration as an option since the overhead wouldn’t be terribly apparent. Currently I’m passing code from the typescript playground to the playcanvas editor, it produce good, readable javascript, but I can code without having to learn a whole new way of checking my code to avoid semantic error.
Async is available in typescript under experimental features anyway, its really just a superset of javascript.


#14

Agree with GreenMoonMoon. I also try to create custom script written in typescript. expcially make pc.createscript work with typescript.
it will be nice, if playcanvas engine team can provide a MonoBehaviour like base class. e.g. class PCBehaviour.


#15

It does? pc.createScript returns a script object: https://github.com/playcanvas/engine/blob/master/src/script/script.js


#16

I want to write code like this, see below.
but KeyboardController_.update never get called

...
box.script.create('KeyboardController_');

keyboardController_.ts

class KeyboardController_ implements PCBehaviour
{
    entity : any;

    initialize() {
        app.keyboard.on(pc.EVENT_KEYDOWN, this.onKeyDown, this);
        app.keyboard.on(pc.EVENT_KEYUP, this.onKeyUp, this);
    }
    update(e:any) {
    var t = 0;
    if(app.keyboard.wasPressed(pc.KEY_LEFT))
    {
        t = -5;
    }
     if(app.keyboard.wasPressed(pc.KEY_RIGHT))
     {
         t = 5;
     }
     //app.keyboard.isPressed(pc.KEY_SPACE) && (t = 1);

     this.entity.rotateLocal(0, t, 0)
    }
    onKeyDown(e:any) {
    // e.key === pc.KEY_A && this.redMaterial && (this.entity.model.meshInstances[0].material = this.redMaterial.resource),
    //     e.event.preventDefault()
        //
    }
    onKeyUp(e:any) {
        // e.key === pc.KEY_A && this.whiteMaterial && (this.entity.model.meshInstances[0].material = this.whiteMaterial.resource)
    }
}
pc.extend(pc,function () {
    var registerPCBehaviour = function (name,behaviour,app) {
        var script = pc.createScript(name,app);
        pc.extend(script,behaviour);
    };
    return {
        registerPCBehaviour : registerPCBehaviour
    };
}());

pc.registerPCBehaviour(“KeyboardController_”,KeyboardController_);


#17

For those interested, I have forked @whydoidoit 's babel-playcanvas-template and modified it for use with TypeScript instead of Babel. It still needs work and your contributions are welcome. https://github.com/Neoflash1979/typescript-playcanvas-template

TODO

  • Improve typings file.
  • Extend PC engine code so that we can use TypeScript style classes when creating a script.

Ideally instead of doing this:

var MyScript = pc.createScript('myScript');

MyScript.attributes.add('myAtt', {
  type: 'string'
});

MyScript.prototype.initialize = function() {
  // Insert awesome game programming stuff here
}

… we could do something that looks more like this:

class MyScript extends ScriptType {
  myAtt: string;
  initialize() {
    // Insert awesome game programming stuff here
  }
}

#18

Instead of monkeying around with the engine code, I wrote a simple wrapper that allows ES6 class syntax. Code here: