Skip to content

new myVariable.constructor() doesn't compile #4356

Closed

Description

@jklmli
class Test {
    num: number;

    constructor(num: number) {
        this.num = num;
    }
}

var t = new Test(1);
var u = new t.constructor(2);

This code throws a compile error, but appears to produce valid code when entered into http://www.typescriptlang.org/Playground.

EDIT:
This code correctly compiles after changing the last line to:

var u = new (<{ new(...args: Array<any>): Test }>t.constructor)(2);

Activity

  1. DanielRosenwasser commented on Aug 19, 2015

    @DanielRosenwasser
    Member

    The compiler will still emit code in the presence of errors unless given the --noEmitOnError flag. Emit in the face of syntactic errors is a best-effort emit with no guarantees in syntactic validity.

  2. jklmli commented on Aug 19, 2015

    @jklmli
    Author

    This code should be supported on all browsers, given https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor.

    I appreciate the --noEmitOnError flag when doing development, but this doesn't help when our CI blocks deploy when there's a compile error, and there's no option to disable errors on lines (a la tslint).

    I strongly object to the By Design tag here, since a better design would be to avoid triggering a compile error at all. The posted workaround is unnecessarily verbose.

  3. changed the title [-]`new myVariable.constructor()` doesn't work[/-] [+]`new myVariable.constructor()` doesn't compile[/+] on Aug 19, 2015
  4. DanielRosenwasser commented on Aug 19, 2015

    @DanielRosenwasser
    Member

    I apologize, I misread the original issue. I thought you were suggesting that the code should not have been emitted at all.

  5. ahejlsberg commented on Aug 20, 2015

    @ahejlsberg
    Member

    The constructor property will only be correct if the constructor function chooses to initialize it. Although TypeScript generates code to do so, it is not a requirement and you can't generally rely on it for an arbitrary constructor function (e.g. one implemented in a JavaScript framework). For that reason TypeScript doesn't strongly type the constructor property.

  6. RyanCavanaugh commented on Aug 21, 2015

    @RyanCavanaugh
    Member

    The constructor property will only be correct if the constructor function chooses to initialize it

    I can't find any evidence supporting this. All runtimes seem to hook this up automatically.

    This code should be supported on all browsers, given https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor.

    I can't find any evidence supporting this, either. The ES spec doesn't define that this property is present as a result of object creation.

    http://www.ecma-international.org/ecma-262/6.0/#sec-evaluatenew
    http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
    http://www.ecma-international.org/ecma-262/6.0/#sec-objectcreate

  7. jklmli commented on Aug 24, 2015

    @jklmli
    Author

    MDN lists the relevant specs near the bottom of the page - this is the most relevant:
    http://www.ecma-international.org/ecma-262/6.0/#sec-object.prototype.constructor

  8. RyanCavanaugh commented on Aug 25, 2015

    @RyanCavanaugh
    Member

    @jiaweihli but all that says is that the actual field Object.prototype.constructor points to Object. It doesn't imply anything about whether or not new'd values automatically get a constructor property.

  9. jklmli commented on Aug 26, 2015

    @jklmli
    Author

    Ryan Cavanaugh (@RyanCavanaugh) I believe the spec is a bit unclear here - it says the field Object.prototype.constructor points to %Object%, which I think refers to the constructor, since it's subclassable.

    This has been the stance of MDN since the earliest version of that page, so that's most likely their interpretation of the ES1 spec. The relevant section begins on page 73 here.

    I don't necessarily have the knowledge needed to resolve this ambiguity, but I think it's worth looking into this since a lot of freely available documentation lists the behavior I mentioned above. Anecdotally, the code has worked for me in several different environments, and is also supported by all major browsers.

  10. kitsonk commented on Aug 26, 2015

    @kitsonk
    Contributor

    @jiaweihli appears to be right. Given the following in Chrome 44:

    class A {
        constructor () {
            console.log('I was called');
        }
    }
    
    let a = new A();
    let aa = new a.constructor();

    a.constructor references A and works as expected.

  11. RyanCavanaugh commented on Aug 26, 2015

    @RyanCavanaugh
    Member

    I get that this works in many runtimes, but I'm still not seeing it being spec'd behavior. Why does the fact that Object.prototype.constructor === Object mean that a.constructor === A ?

  12. kitsonk commented on Aug 27, 2015

    @kitsonk
    Contributor

    Correct me if I am wrong, but doesn't %Object% refer to the intrinsic value of the current realm, ergo the current execution context, therefore a.constructor === A:

    19.1.3.1 Object.prototype.constructor

    The initial value of Object.prototype.constructor is the intrinsic object %Object%.

    And intrinsic objects are described as:

    Within this specification a reference such as %name% means the intrinsic object, associated with the current Realm, corresponding to the name.

  13. mhegazy commented on Aug 27, 2015

    @mhegazy
    Contributor

    Pinging Brian Terlson (@bterlson) for this one.

  14. bterlson commented on Aug 28, 2015

    @bterlson
    Member

    I think you can strongly type constructor for ES6 classes. The constructor property is added to the C.prototype in ClassDefinitionEvaluation step 18. It is configurable, though, so users could presumably delete it (GeneratorFunction instances, notably, do not have a constructor property on their [[prototype]] for reasons users might also find compelling - not leaking a reference to the constructor when vending instances IIUC).

    People above are also correct that Object.prototype has a constructor property that points to Object (and thus any object with Object.prototype in its prototype chain and no other constructor properties will have a .constructor property pointing to Object). But I don't think this has any bearing on whether you can strongly type the .constructor property of class instances.

  15. RyanCavanaugh commented on Sep 28, 2015

    @RyanCavanaugh
    Member

    Duplicate of #3841

  16. RyanCavanaugh commented on Mar 7, 2016

    @RyanCavanaugh
    Member

    Reopening since #3841 is for the static side whereas this is for the instance side

  17. RyanCavanaugh commented on Jun 23, 2021

    @RyanCavanaugh
    Member

    Let's track at #4586

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

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions