Why does TypeScript pack a class in an IIFE?
It's done to preserve native class behavior in edge cases like this, where someone tries to use class Greeter
before it's defined:
// this is javascript code, not TypeScript
console.log(Greeter.What());
class Greeter {
}
Greeter.What = function What() {
return "Greater";
}
With native class implementation, this should print ReferenceError: Greeter is not defined
.
When transpiled and wrapped in IIFE, the result is close enough: TypeError: Cannot read property 'What' of undefined
.
Without IIFE, unwrapped function is hoisted and name Greeter
is in scope before it's defined, so the different error is produced: TypeError: Greeter.What is not a function
Note that IIFE is not used to hide private instance or class properties because it's not necessary anyway. When transpiled, instance properties are assigned as properties for this
inside the constructor, and static properties are assigned as properties of Greeter
object - no variables are created.
TypeScript will pass arguments to the IIFE in cases where there is inheritance between classes. For example, the closure below is used when Greeter
extends a BaseGreeter
class:
var Greeter = /** @class */ (function (_super) {
// __extends is added by the TS transpiler to simulate inheritance
__extends(Greeter, _super);
function Greeter(subject) {
var _this = _super.call(this) || this;
_this.subject = subject;
return _this;
}
Greeter.What = function () {
return "Greater";
};
Greeter.prototype.greet = function () {
return "Hello, " + this.subject;
};
return Greeter;
}(BaseGreeter));