Ember and TypeScript

We’re looking into best practices for writing ember controllers and components using TypeScript. One of the things I’m having trouble with is how to model Ember.Object.extend in a first-class way using TypeScript’s class inheritance (so we get the benefits of TypeScript’s intellisense and strong typing). For example, a simple controller with a method and an action is traditionally written as:

var CustomController = Ember.Controller.extend({
    say: function() {
        console.log("say hi");
    },

    actions: {
        hello: function() {
            console.log("hello");
        }
    }
});

I’m trying to model controllers as classes, and a first cut would be:

class CustomController extends Ember.Controller {
    public say() {
        console.log("say hi");
    }
}

But I’m not able to figure out how to create the actions hash on the class such that it gets properly picked up in the same way as Ember.Object.extend. Creating actions as a member variable or static variable doesn’t work. Does Ember.Object.extend do something special that we’re missing when we just use regular prototypical inheritance? Any ideas on how to solve this would be much appreciated.

Thanks!

3 Likes

I’d like to know how to do this as well. Hopefully this can get a bump. I haven’t seen a good best practice for emberjs and ts yet…

Would be happy to help. Could you share an example somehow so I can debug?

CoffeeScript has a similar issue that led to the creation of http://emberscript.com/. I gave it a shot but eventually ended up just avoiding CoffeeScript classes entirely when extending built in Ember Objects.

I don’t really know enough about TS to comment, but Ember.Object.create seems to be geared towards accomplishing the exact same goals in regards to inheritance as the various preprocessors out there, so there is a of conflict.

That’s what I’m thinking too. But plain old javascript hurts…

Any progress on this? I love Typescript and would like to be able to use it with Ember.js

I dont think you can do it in the way you described of the post because it would require you to adjust typescripts compile to change behaviour when it extends any of the Ember classes.

I might have managed to produce something very simple with typescript though

/**
 * The module of all ember controllers in my application.
 */
module EmberApp.Controllers {
    /**
     * Transforms the javascript object to an extension of an ember class.
     * @param emberClass The ember class to extend.
     * @param toExted The javascript object to extend on the given ember class.
     */
    export function transformTo(emberClass: any, toExtend: any) {
        return emberClass.extend(toExtend);
    }

    /**
     * The base controller to be extended.
     */
    export class BaseController {
        /**
         * Converts the instance of this object to the Ember controller you want
         * @returns The Ember controller of this object.
         */
        convertToEmber() {
            return <Ember.Controller>Ember.Controller.extend(this);
        }
    }
    
    /**
     * The custom controller for testing purposes.
     */
    export class CustomController extends BaseController {
        /**
         * The actions variable that will be used for ember.
         */
        public actions = {
            /**
             * The hello action used in ember.
             */
            hello: () => {
                console.log("hello");
            }
        }
        
        /**
         * The say function of this controller.
         * 
         * NOTE: I am not sure if the prototyped function will be taken by ember.
         */
        public say() {
            console.log("say hi");
        }
    }
}

var customController = new EmberApp.Controllers.CustomController().convertToEmber();
console.log(customController);

Which compiles to

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};

var EmberApp;
(function (EmberApp) {
    /**
    * The module of all ember controllers in my application.
    */
    (function (Controllers) {
        /**
        * Transforms the javascript object to an extension of an ember class.
        * @param emberClass The ember class to extend.
        * @param toExted The javascript object to extend on the given ember class.
        */
        function transformTo(emberClass, toExtend) {
            return emberClass.extend(toExtend);
        }
        Controllers.transformTo = transformTo;

        /**
        * The base controller to be extended.
        */
        var BaseController = (function () {
            function BaseController() {
            }
            /**
            * Converts the instance of this object to the Ember controller you want
            * @returns The Ember controller of this object.
            */
            BaseController.prototype.convertToEmber = function () {
                return Ember.Controller.extend(this);
            };
            return BaseController;
        })();
        Controllers.BaseController = BaseController;

        /**
        * The custom controller for testing purposes.
        */
        var CustomController = (function (_super) {
            __extends(CustomController, _super);
            function CustomController() {
                _super.apply(this, arguments);
                /**
                * The actions variable that will be used for ember.
                */
                this.actions = {
                    /**
                    * The hello action used in ember.
                    */
                    hello: function () {
                        console.log("hello");
                    }
                };
            }
            /**
            * The say function of this controller.
            *
            * NOTE: I am not sure if the prototyped function will be taken by ember.
            */
            CustomController.prototype.say = function () {
                console.log("say hi");
            };
            return CustomController;
        })(BaseController);
        Controllers.CustomController = CustomController;
    })(EmberApp.Controllers || (EmberApp.Controllers = {}));
    var Controllers = EmberApp.Controllers;
})(EmberApp || (EmberApp = {}));

var customController = new EmberApp.Controllers.CustomController().convertToEmber();

I am still a beginner in Ember, so could anyone verify if this works?

2 Likes

Has the status of Ember and Typescript changed since all the talk from the typescript developers that they consulted the Ember team regarding the AtScript - Typescript merger?

I would really like to use Typescript for an ember project as i come from a VisualStudio / C# background and am really, really attached to syntax checking and intellisense.

@Kilowhisky fwiw, Ember’s get/set pattern means much of the typing benefits are un-realized. You cannot rely on the automatic typing like you can if you access some.property, instead you have a get function that always returns an any.

Additionally, Ember’s object model is not understood by TypeScript. We have a ways to go before using straight ES6 classes and decorators. The future for this is bright, but we aren’t quite there yet.

The AtScript/TypeScript merger is based on TC39 finally coming to an agreement about annotations and decorators. We’ve been looking forward to using decorators for a long time, and we’re eager to be using them and ES6 classes as soon as it is practical.

There has been some discussion about TypeScript offering their type checking as stand-alone layer without their ES5 transpilation. This would be ideal for Ember and the community in general, as devs would be free to choose any of a number of ES transpilers with TypeScript layered on top of any of them.

3 Likes

I’m also very interested in Typescript. Because I use Ember a lot I’m also curious how to combine these two things. Are there any projects going on, which are focusing on Ember and Typescript?

As @mixonic pointed out Ember’s get/set makes it “impossible” to typecheck so I wonder if it makes any sense to use Typescript. Especially on afternoons (after some hard workday) intellisense/code completion would be awesome :smiley:

I would be happy to hear some stories of people using Ember with Typescript.

I’m also interested in TypeScript. Are there any plans to support it by Ember??

I’m following Ember and also did some side projects with it. I also like TypeScript and a combination would be nice :slight_smile: yesterday I saw that glimmer is mainly written in TypeScript so I wonder if there are any news of Ember and TypeScript?

The new Glimmer Engine is written in TypeScript. If Ember’s core component uses TS, I’m sure this option will appear soon for everybody. Fingers crossed.

1 Like

@zoltan let’s hope so :smile:

1 Like

@tomdale: I’m sold too :smile: when do we get TypeScript in Ember :smile:

I’d love to see support for using TypeScript with Ember - I’m a believer in TypeScript for enterprise projects.

A very interesting read about why libraries should be authored in TypeScript: André Staltz - All JS libraries should be authored in TypeScript

Hopefully Ember will be authored in TypeScript one day too :slight_smile:

Some of it already is.

We wrote a pretty extensive library that makes heavy use of Ember and its Object Model. I wrote a class that lets me define Typescript that actually “inherits” from Ember.Object. This gives me Typescript typings at authorship/compile time, but uses Ember mechanics under the hood. I haven’t written this for other objects in the Ember hierarchy because our library didn’t need it yet, but maybe this will be helpful for other folks?

5 Likes

As @mixonic has pointed out Ember get/set pattern remains the main burden that hugely decreases the benefit of adopting Typescript in Ember apps. However now when Static types for dynamically named properties is up in Typescript 2.1 there is a hope that the situation might change. There are still some design limitations which would not allow to properly describe the get/set pattern with it but we as a community can really push that change to happen as Microsoft accepts language design proposals into consideration those who are interested in bringing Ember-Typescript stack forward are welcome to review/comment/support the following proposal i have put up to make Ember get/set pattern type aware - Feature request: Multiple level deep Static types for dynamically named properties. · Issue #12407 · microsoft/TypeScript · GitHub

2 Likes