This behaviour seems fairly well documented (See Initializing variables inline during declaration vs in the constructor in Angular with TS here on SO for example), but it can cause some really hard to track down memory issues.
See the following example
class Bar {
private num: number;
private closure: any;
constructor(num: number, closure : any) {
this.num = num;
this.closure = closure;
}
}
class Foo {
private bar = new Bar(5, (a: number, b: number) => {return a < b;});
private baz: number;
constructor(very_expensive_thing: any) {
this.baz = very_expensive_thing.small_thing;
}
}
If this would have been plain old javascript, there would be no issue as the Bar
initialiser has no access to the very_expensive_thing
object.
However, typescript inlines the initialiser of Bar into the constructor
and as such it now retains the very_expensive_thing
, see generated javascript from the typescript playground v5.1.3:
"use strict";
class Bar {
constructor(num, closure) {
this.num = num;
this.closure = closure;
}
}
class Foo {
constructor(very_expensive_thing) {
this.bar = new Bar(5, (a, b) => { return a < b; });
this.baz = very_expensive_thing.small_thing;
}
}
The retaining of a constructor parameter inside the closure is not intuitive and does not follow normal scoping rules.
While the fix is trivial (move the closure out of the class), it would be great to hear from more experienced typescript users whether this is a known pitfall or should be treated as an issue. Is there anyway to turn off the inlining behaviour to prevent this?