Typescript: Why are TS get/set definedProperties in a class transpiled as enumerable/writable?

Created on 24 Jun 2015  Â·  13Comments  Â·  Source: microsoft/TypeScript

I just confirmed in the TS Playground that the following TS:

class Foo {
    get bar() { return true;}
}

Produces this JS:

var Foo = (function () {
    function Foo() {
    }
    Object.defineProperty(Foo.prototype, "bar", {
        get: function () { return true; },
        enumerable: true,
        configurable: true
    });
    return Foo;
})();

This MDN link confirms that, for Object.definedProperty accessors:
• enumerable: Defaults to false.
• configurable: Defaults to false.

Clearly the generated code is overriding the default values for these keys.

Plowing through the ES6 spec is not something I do. So I’m not sure that ES6 hasn’t changed the defaults. But I’d be surprised.

Now one of the things I miss in TS/ES6 class definitions is the ability to control these keys. It is also not easy to embellish a class with defined properties later … properties that might have non-default definitions

But that’s not my point or my question … which is, why is TS deviating from the defaults?

I get why I’d want the property to be enumerable most of the time – strange that the spec defaults to false. I don’t understand why I should want it to be configurable (maybe because I don't like something about the property TS generated for me?).

In any case, I don’t get how TS (or ES6) gets away with changing the ES5 defaults.

Breaking Change Committed ES6 Suggestion help wanted

Most helpful comment

Is anyone doing this work?
I met this issue in SkateJS.
SkateJS wrote by Babel. SkateJS expected inherit static member of enumerable: false.
But TypeScript can't inherit it.

All 13 comments

This might actually be a bug.

14.5.14 Runtime Semantics: ClassDefinitionEvaluation

With parameter className.

    _ClassTail_ : _ClassHeritage_opt { _ClassBody_opt }

[...]
For each _ClassElement_ _m_ in order from _methods_

  1. If IsStatic of _m_ is false, then

    1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _proto_ and false.

  2. Else,

    1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _F_ and false.

That second parameter to PropertyDefinitionEvaluation is _enumerable_.

Though, PropertyDefinitionEvaluation sets [[Enumerable]] to true, so the current behavior may be correct in that respect. (referenced wrong section)

This part of the spec is hard to trace and it would be good to have more eyes on this if possible.

/CC: @bterlson

Sorry for polluting this discussion, but why isn't the result code just use ES5 getters/setters ? Why use defineProperty?

@gilamran you want to put the instance getters/setters on the prototype of the constructor function, and the static ones on the function itself. there is no other way to create something that is both a function, and set properties on it. you can do this with object literals, but then they are not functions.

@mhegazy Got it, thanks!

Sorry I'm late to this thread...

Class methods and getters/setters are created with enumerable false, configurable true, writable true. Seems like an ES6 conformance bug.

(The rationale here was in part to align classes with the built-in types, eg. consider that Array.prototype.* are non-enumerable).

Thanks for clarifying @bterlson, and thanks for noticing @wardbell.

We should change our emit to align with the ES6 semantics. This will be a breaking change (probably a large one, relatively speaking), but is required for ES5/ES6 compat.

I believe I've run into this issue. Here is a repeatable snippet that works as intended when targeting es6 or using Babel.
link

Is anyone doing this work?
I met this issue in SkateJS.
SkateJS wrote by Babel. SkateJS expected inherit static member of enumerable: false.
But TypeScript can't inherit it.

Any updates on this?

I see this is still an issue in 2018.

This is clearly a bug. There is an obvious functional difference in the code generated when targeting es5 and when targeting es6.

I'm working with code that depends on properties being non-enumerable, so TypeScript targeting es5 simply produces broken code. I believe relying on properties being non-enumerable is a reasonable thing to do, especially given this is the behaviour of all current es6 browsers.

Please consider fixing this. If there is too much impact on existing code then an option to control the output variant would be useful and allow a graceful change-over period.

image

Was this page helpful?
0 / 5 - 0 ratings

Related issues

weswigham picture weswigham  Â·  3Comments

MartynasZilinskas picture MartynasZilinskas  Â·  3Comments

fwanicka picture fwanicka  Â·  3Comments

wmaurer picture wmaurer  Â·  3Comments

DanielRosenwasser picture DanielRosenwasser  Â·  3Comments