Repository navigation
Computed Properties aren't bound correctly during Object/Class evaluation #27864
Description
Activity
There's a type error on the line with the computed property:
A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
However
- It's still possible to produce correct emit in this case, even though there's a type error (if that's desirable)
- The class fields proposal allows code like in the example. Chrome Canary implements the spec and produces the expected output for the example code.
Reacted by Daniel Rosenwasser and Rob Palmer- ghost addedDomain: API: TransformsRelates to the public transform APIRelates to the public transform API
on Oct 12, 2018 - addedHelp WantedYou can do thisYou can do thisEffort: ModerateRequires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual".Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual".
on Oct 12, 2018 DanielRosenwasser commented
on Oct 12, 2018 MemberMore actionsTaking PRs and marking it as moderate (assuming you are familiar with spec-reading and the transform pipeline).
What are the implications of getting rid of the type error? Will allowing arbitrary string and symbol values in computed field declarations affect inference?
Type errors aside, here's one possible emit that works correctly. I haven't seen any other cases of invoking an IIFE with parameters like this. Are there any?
var classes = []; for (var i = 0; i <= 10; ++i) { classes.push( function(i) { function A() { this[i] = "my property"; } return A; }(i) ); }Maybe we can lean on the iife stuff that's already done to transpile
letandconst.The currently generated code for Joey's example when targeting ES2015 is:
var _a, _b; "use strict"; const classes = []; for (let i = 0; i <= 10; ++i) { classes.push((_b = class A { constructor() { this[_a] = "my property"; } }, _a = i, _b)); } for (const clazz of classes) { console.log(Object.getOwnPropertyNames(new clazz())); }
If we move
_aand_binto the containing scope of the class and useletthen the output is correct:"use strict"; const classes = []; for (let i = 0; i <= 10; ++i) { let _a, _b; // <---- was moved classes.push((_b = class A { constructor() { this[_a] = "my property"; } }, _a = i, _b)); } for (const clazz of classes) { console.log(Object.getOwnPropertyNames(new clazz())); }
Update: would this be a big architectural change? If I understand correctly,
lexicalEnvironmentStackis used in hoisting declarations, and is defined in transformer.ts, rather than in a particular transformer.the special temporary variable and hoist is happened in ts transformer before es2015
perhaps we need a block level hoist?- added a commit that references this issue
on Oct 26, 2018 Wenlu Wang (@Kingwl) agreed.
we're trying that approach in joeywatts#15
used that approach in #28708- removed this from the TypeScript 3.2 milestone
on Nov 13, 2018 2 remaining items
- added 4 commits that reference this issue
on Nov 15, 2018 joeywatts commented
on Nov 29, 2018 ContributorAuthorMore actionsI noticed that there's also an issue with the binding of property declaration initializers in class expressions which are within an iteration statement. For example:
let arr = []; for (let i = 0; i < 5; ++i) { arr.push(class C { test = i; }) } arr.forEach(clazz => console.log(new clazz().test));
Since the
iis block scoped within the loop, each class should capture its own value ofi(causing it to print 0, 1, 2, 3, 4). The TypeScript compiler currently does not preserve this binding when targeting ES5 or lower. This currently produces no compile error and leads to different run time behavior when targeting ES2015 vs ES5.I've investigated the changes required to the checker in order to pick up this binding, and it appears to me that a simple change to the
checkNestedScopeBindingfunction to account for usage sites within instance property initializers (in addition to functions) would work. Should I open a separate issue for this?RyanCavanaugh commented
on Jul 23, 2025 MemberMore actionsOutput is correct now
- locked as resolved and limited conversation to collaborators
on Jan 20, 2026
TypeScript Version: 3.2.0-dev.20181011
Search Terms: computed property expression
Code
Expected behavior: The log statements indicate that each class in
classeshas a different property name (ishould be evaluated at the time of the class evaluation and all instances of that class should have a property name corresponding to that evaluation ofi).Actual behavior: Compiled code logs:
Playground Link