Skip to content

Add explicit error to __extends when base class is undefined #5794

Closed

Description

@Arnavion

We occasionally get people in the IRC channel asking about their transpiled JS failing with TypeError: undefined is not an object. It happens when accessing b.prototype inside __extends because the child class is before the base class, but they often think it's a bug in __extends. Would it make sense to detect if b is undefined at the start of the function and throw an appropriately worded error? Eg:

var __extends = this.__extends || function (d, b) {
    if (b === undefined) { throw new Error("The base class is not defined. Did you put the child class before the base class?"); }
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};

Activity

  1. mhegazy commented on Nov 26, 2015

    @mhegazy
    Contributor

    would #4343 be sufficient to address the underlying problem?

  2. Arnavion commented on Nov 26, 2015

    @Arnavion
    Author

    It seems to me that PR only detects child before base in the same file? Does it handle, say, base class imported from another module that also has circular reference so base class is still undefined?

  3. frankwallis commented on Nov 26, 2015

    @frankwallis
    Contributor

    Coincidentally the circular referenced superclass issue came up on stack overflow just the other day: http://stackoverflow.com/questions/33897273/typescript-and-systemjs-circle-dependency/33905499#33905499

  4. mhegazy commented on Dec 1, 2015

    @mhegazy
    Contributor

    It seems to me that PR only detects child before base in the same file? Does it handle, say, base class imported from another module that also has circular reference so base class is still undefined?

    you are correct, it does not handle circular references in modules, just in the same file, or if you are using --out.

  5. RyanCavanaugh commented on Dec 1, 2015

    @RyanCavanaugh
    Member

    The other common case I see is that someone refactors into two script files and forgets to add a script tag for the file containing the base class.

  6. DavidKDeutsch commented on Mar 14, 2016

    @DavidKDeutsch

    Out of curiosity, has the implementation of __extends changed recently? Ever since upgrading to 1.8, I seem to get these run time errors a lot more. Not sure if it is just a coincidence or what.

  7. Arnavion commented on Mar 14, 2016

    @Arnavion
    Author

    David Deutsch (@DavidKDeutsch) __extends is not the source of the problem (base class being undefined). It's the messenger. That's what this issue is about - of clarifying that the problem is not with __extends but with whether the classes are defined / loaded in the right order or not.

    If you're seeing it more with 1.8 then it might be 1.8 changed the ordering of your classes such that the base class is undefined (although it sounds unlikely).

  8. DavidKDeutsch commented on Mar 14, 2016

    @DavidKDeutsch

    BTW, this can be especially confusing to developers when including other libraries that were also compiled with TypeScript, as the first file that defines __extends is where the error is thrown from.

  9. yssource commented on May 16, 2016

    @yssource

    I am having the same issue even if the class is used after the other:

    BaseClass.ts:

    module MyModule {
      export class Base {
        constructor() { }
      }
    }
    

    ChildClass.ts:

    module MyModule {
      export class Child extends Base {
        constructor() { super(); }
      }
    }
    

    Generates:

    /****************************************************************************
      Generated by T4TS.tt - don't make any changes in this file
    ****************************************************************************/
    
    var MyModule;
    (function (MyModule) {
      /** Generated from MyModule.Base **/
      var Base = (function () {
        function Base () {
        }
        return Base;
      })();
      MyModule.Base = Base;
    })(MyModule || (MyModule = {}));
    
    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 MyModule;
    (function (MyModule) {
      /** Generated from MyModule.Child **/
      var Child = (function (_super) {
          __extends(Child, _super);
          function Child() {
              _super.apply(this, arguments);
          }
          return Child;
      })(MyModule.Base);
      MyModule.Child = Child;
    })(MyModule|| (MyModule = {}));
    

    It seems that the order is correct, although it doesn't look like it is working as expected.

    But if I am merging two source files into one, then it is working well.

    BaseClassAndChileClass.ts:

    module MyModule {
      export class Base {
        constructor() { }
      }
      export class Child extends Base {
        constructor() { super(); }
      }
    }
    
  10. added this to the milestone on Jan 4, 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

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions