Skip to content

Add ability to specify the external __extends function #2009

Description

Currently when implementing of class inheritance in the output JS-file automatically added the following code:

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 __();
};

And calls of the following kind:

__extends(MyClass, _super);

In the presence of large amount of TS-files in the project, this leads to a significant increase size of concatenated file (especially when using AMD-modules).

It would be nice to add a new compiler option (it can be called externalExtendsFunction), which would be allow to specify the name of analog __extends function from external script. For example, if we set to the externalExtendsFunction option a value equal to util.extends, then the __extends function code will not be generated in the JS-file and its calls will be as follows:

util.extends(MyClass, _super);

Activity

  1. danquirk commented on Feb 11, 2015

    @danquirk
    Member

    Are you using the latest bits? #1350 was fixed by #1356 which should stop multiple __extends from being emitted often. The implementation of __extends already permits being overridden by your own (if this.__extends exists).

  2. Taritsyn commented on Feb 12, 2015

    @Taritsyn
    Author

    I build tsc.js from commit f2c98ba95eebfd544aa17d479ed574d59bd7bef1 and tried to compile an example from the "Don't emit __extends if one is already in scope #1356" issue. And I got the following result:

    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 M;
    (function (M) {
        M.__extends = function () { };
        var A = (function () {
            function A() {
            }
            return A;
        })();
        var B = (function (_super) {
            __extends(B, _super);
            function B() {
                _super.apply(this, arguments);
            }
            return B;
        })(A);
    })(M || (M = {}));
    

    Then I found out, that this pull request was not merged to the master branch. But such a solution is unlikely to be help when compiling of external modules with a single export:

    class A {
        foo(): void {
            alert('foo');
        }
    }
    
    class B extends A {
        bar(): void {
            alert('bar');
        }
    }
    
    export = B;
    

    I use a single exports when creating a view models in Durandal. Here we need a more comprehensive solution of problem (similar to what I suggested).

    By the way, I noticed that even if the target option equals to es6, then class inheritance anyway is implemented by using the __extends function instead of using the native ECMAScript 6 class inheritance.

  3. danquirk commented on Feb 12, 2015

    @danquirk
    Member

    Ah, sorry about that, I also didn't notice we never merged that. There're apparently some additional cases that aren't handled by that PR yet. I logged #2022 for the ES6 part.

  4. tomitrescak commented on Jun 10, 2015

    @tomitrescak

    Hi, the documentation says that "noEmitHelpers" flag is supported now, but using it with 1.5.0-Beta does not do anything? Is there any particular release I should be using? Thanks.

  5. mhegazy commented on Jun 11, 2015

    @mhegazy
    Contributor

    This was added after 1.5-beta, so it should be in the next release 1.5.2

  6. tomitrescak commented on Jun 11, 2015

    @tomitrescak

    Thanks for the info! Any estimate on when it will be?

  7. mhegazy commented on Jun 11, 2015

    @mhegazy
    Contributor

    we usually like to stabilize a release for a few weeks before it is released. We are not adding any more features just big fixes at the point. So hopefully soon.

  8. mikemorton commented on Aug 28, 2015

    @mikemorton

    noEmitHelpers is working well for me, but I was curious if there was a pre-created Helpers File that would be easy for me to simply include in my project?

  9. mhegazy commented on Aug 31, 2015

    @mhegazy
    Contributor

    Mike Morton (@mikemorton) there is not one, but here is what i would put:

    var __extends = (this && this.__extends) || function (d, b) {
        for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
    var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
        if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
        switch (arguments.length) {
            case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
            case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
            case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
        }
    };
    var __metadata = (this && this.__metadata) || function (k, v) {
        if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
    };
    
    var __param = (this && this.__param) || function (paramIndex, decorator) {
        return function (target, key) { decorator(target, key, paramIndex); }
    };
    
    var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
        return new Promise(function (resolve, reject) {
            generator = generator.call(thisArg, _arguments);
            function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
            function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
            function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
            function step(verb, value) {
                var result = generator[verb](value);
                result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
            }
            step("next", void 0);
        });
    };
  10. mhegazy commented on Aug 31, 2015

    @mhegazy
    Contributor

    this is handled with the --noEmitHelpers as stated above.

  11. locked and limited conversation to collaborators on Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions