Skip to content

Wrong constructor of Error subclass from 2.1.1 #12660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
marty-wang opened this issue Dec 5, 2016 · 4 comments
Closed

Wrong constructor of Error subclass from 2.1.1 #12660

marty-wang opened this issue Dec 5, 2016 · 4 comments
Labels
Duplicate An existing issue was already created

Comments

@marty-wang
Copy link

marty-wang commented Dec 5, 2016

TypeScript Version: 2.1.1 / nightly (2.2.0-dev.201xxxxx)

Code

// A *self-contained* demonstration of the problem follows...
class MyError extends Error {
    public code: number;
    constructor(code: number, message: string) {
        super(message);
        this.code = code;
    }
}

const e = new MyError(0, "foo");

Expected behavior:
e instanceof MyError === true;
Actual behavior:
e instanceof MyError === false

Note: it was working for ts 2.0.10, but not for ts 2.1.1

@marty-wang marty-wang changed the title Wrong subclass constructor from 2.1.1 Wrong constructor of Error subclass from 2.1.1 Dec 5, 2016
@HerringtonDarkholme
Copy link
Contributor

#12123

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Dec 5, 2016
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Dec 5, 2016

A summary of what's going on based on a conversation with @rbuckton:

  1. This didn't "work" in any meaningful sense in 2.0 -- the base constructor didn't properly run due to how weird internal objects like Error get constructed. See footnote*
  2. This isn't possible to make work in regular ES5 because you need to do some prototype/proto hackery that can't be emulated without ES6 APIs
  3. Targeting ES6 this is fine because you'll just have native class emit anyway

Possible fixes: Either don't use instanceof with custom classes, don't try to extend weird built-ins, or target ES6.

* Code:

class Foo extends Error {
    constructor() {
        super("oh no");
    }
}
let x = new Foo();
// Expected: x.message === "oh no"
// Actual: x.message === ""
alert(x.message);

See also http://stackoverflow.com/a/17891099/1704166

@mhegazy
Copy link
Contributor

mhegazy commented Dec 5, 2016

My recommendation to get this working is to set the prototype explicitly on your instances. for instance:

class MyError extends Error {
    sayHello() {
        return "hello " + this.message;
    }
    constructor(m) {
        super(m);

        // Set the prototype explictilly
        Object.setPrototypeOf(this, MyError.prototype);
    }
}


var e = new MyError("my error");

console.log("e instanceof Error => " + (e instanceof Error)); // true
console.log("e instanceof MyError => " + (e instanceof MyError)); // true
console.log("e.message  => " + (e.message)); // "my error"
console.log("e.sayHello()  => " + (e.sayHello()));  // "hello my error"

The only change here from extending non-built-in classes is Object.setPrototypeOf(this, MyError.prototype);

alternatively, you can just set this.__proto__ instead of using Object.setPrototypeOf`

@Yaojian
Copy link

Yaojian commented Jun 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants