Skip to content

Subclass extends Error is broken #14702

Closed
@omochi

Description

@omochi

Summary

Subclass extends Error is broken.
If I define subclass and construct instance of it with new,
I get instance of Error but not instance of subclass.
So If I call instance method of this instance, it will crash.
And If I use instanceof operator to it, it return false.

TypeScript Version: 2.2.1

Code

// a.ts
class MyError extends Error {
    greet() {
        console.log("I am MyError!");
    }
}

let e = new MyError();
console.log(e instanceof MyError);
e.greet();

Compile and run

[omochi@omochi-MB ts-inst]$ $(npm bin)/tsc --version
Version 2.2.1
[omochi@omochi-MB ts-inst]$ node --version
v7.7.2
[omochi@omochi-MB ts-inst]$ $(npm bin)/tsc --target ES3 a.ts
[omochi@omochi-MB ts-inst]$ node a.js

Expected behavior:

Print true and I am MyError! on console.

Actual behavior:

Crash with this stacktrace.

false
/Users/omochi/temp/ts-inst/a.js:22
e.greet();
  ^

TypeError: e.greet is not a function
    at Object.<anonymous> (/Users/omochi/temp/ts-inst/a.js:22:3)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:425:7)
    at startup (bootstrap_node.js:146:9)
    at bootstrap_node.js:540:3

My investigation

I tested this with some other configuration.

tsc version target version result
2.0.0 ES3 OK
2.0.0 ES2015 OK
2.2.1 ES3 NG
2.2.1 ES2015 OK
2.3.0-dev.20170316 ES3 NG
2.3.0-dev.20170316 ES2015 OK

What attract me is |2.0.0|ES3|OK|.

With 2.0.0, compiled constructor is below.

var MyError = (function (_super) {
    __extends(MyError, _super);
    function MyError() {
        _super.apply(this, arguments);
    }
    return MyError;
}(Error));

With 2.2.1, compiled constructor is below.

var MyError = (function (_super) {
    __extends(MyError, _super);
    function MyError() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    return MyError;
}(Error));

The difference is return value of MyError().
In 2.0.0, it returns undefined.
In 2.2.1, it returns instance from _super.apply(this, arguments) which is instance of Error but not MyError.

According what I hear, this change of constructor implementation is come from spec of ECMA2015.
But with ES2015 target compile, tsc generated raw JavaScript class syntax and It run correctly. (So compiled result javascript is almost same with source typescript)
So I think this behavior with ES3 target is bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions