What is the reason behind TypeScript enclosing a class within an IIFE (Immediately Invoked Function

Behold the mighty TypeScript class:

class Saluter {
    public static what(): string {
        return "Greater";
    }

    public target: string;

    constructor(target: string) {
        this.target = target;
    }

    public salute(): string {
        return "Greetings, " + this.target;
    }
}

When TS aims for ES5, it morphs into an IIFE:

var Saluter = /** @class */ (function () {
    function Saluter(target) {
        this.target = target;
    }
    Saluter.what = function () {
        return "Greater";
    };
    Saluter.prototype.salute = function () {
        return "Greetings, " + this.target;
    };
    return Saluter;
}());

Nevertheless, it behaves similarly when presented as a traditional constructor function. It looks more like JavaScript in its natural state :)

function Saluter(target) {
    this.target = target;
}
Saluter.what = function () {
    return "Greater";
};
Saluter.prototype.salute = function () {
    return "Greetings, " + this.target;
};

Application:

Both versions function identically:

Greater.what();  // -> "Greater"
var greeter = new Greater("Universe!");
greeter.greet(); // -> "Hello, Universe!

What are the advantages or reasons for wrapping it in an IIFE?

I conducted a basic benchmark test:

console.time("Saluter");
for(let i = 0; i < 100000000; i++) {
    new Saluter("world" + i);
}
console.timeEnd("Saluter");

The results exhibited virtually identical instantiation speeds. This is expected since the IIFE is only resolved once.

I pondered if it might be due to closure, but the IIFE doesn't accept arguments. So, it cannot be a closure.

Answer №1

When classes are inherited, TypeScript will automatically pass arguments to the Immediately Invoked Function Expression (IIFE). An example of this can be seen in the code snippet below where Greeter extends a BaseGreeter class:

var Greeter = /** @class */ (function (_super) {
    // The __extends method is included by the TS transpiler to mimic 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));

Answer №2

To ensure proper functionality of native classes in specific scenarios like this one, precautions must be taken to prevent issues that may arise when attempting to utilize a class such as Greeter before it has been declared:

// The following code snippet is written in JavaScript, not TypeScript

console.log(Greeter.What());

class Greeter {
}

Greeter.What = function What() {
    return "Greater";
}

If using native class implementation, the expected output should be

ReferenceError: Greeter is not defined
.

Once transpiled and enclosed within an Immediately Invoked Function Expression (IIFE), the outcome is similar:

TypeError: Cannot read property 'What' of undefined
.

In cases where an IIFE is omitted, an unwrapped function gets hoisted and the name Greeter exists in the scope prior to its definition, resulting in a different error message:

TypeError: Greeter.What is not a function

It's important to note that IIFE isn't utilized for concealing private instance or class properties due to its unnecessary nature. Upon transpilation, instance properties are assigned as constructor properties using this, while static properties are set as properties of the Greeter object - no additional variables are introduced.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The function purported by WEBPACK_MODULE_13___default(...) does not exist

Scenario : I've been working on a small library (let's call it myLibrary) using TypeScript and Webpack. Everything seemed to be running smoothly until I imported the library into a React application, which resulted in a crash. On the Library Sid ...

Ways to invoke the function in a separate component

How can I use ViewChild to call a method in a different component? I have a method in the piechart component that I want to access from the app component using ViewChild. In my piechart.component.ts file: export class PiechartComponent { constructor() ...

The JokesService (?) has encountered dependency resolution issues that Nest is unable to resolve

Currently delving into the world of NestJS and feeling a bit perplexed about the workings of "modules". In my project, I have two modules namely JokesModule and ChuckNorrisApiModule. My goal is to utilize the service provided by ChukNorrisService within th ...

Break apart the string and transform each element in the array into a number or string using a more specific type inference

I am currently working on a function that has the ability to split a string using a specified separator and then convert the values in the resulting array to either strings or numbers based on the value of the convertTo property. Even when I call this fun ...

What is the best way to transform an array of objects into a nested array through shuffling

I am dealing with a diverse array of objects, each structured in a specific way: data = [ { content: { ..., depth: 1 }, subContent: [] }, { content: { ..., depth: 2 ...

Displayed even when data is present, the PrimeNg empty message persists

I have set up a PrimeNg table to display data with an empty message template like this: <ng-template pTemplate="emptymessage"> <tr> <td> No records found </td> </tr> </ng-template> ...

Download a collection of base64 images as a ZIP file in Angular 4

I am currently developing an Angular2 v4 app using Typescript and I'm looking for a solution to download multiple images (in base64 format) as a Zip file. For instance, I have a sample array like this (containing fake base64 images just for illustrat ...

Loading dynamic content within Angular Material tabs allows for a more customized and interactive user experience

I am currently working on creating a dynamic tab system using Angular Material: Tabs. I have encountered an issue with loading content on tabs after the initial one, where the functionality only works when the first tab is loaded. Below you can see the ta ...

Flag is activated to retrieve the data from the @Input source

@Input() config= []; flag = false; I need to change the flag to true only when I receive data in the config from the @input. Where should I do this? The data in the config is delayed and I am unable to access it in ngOnInit but can get it in ngOnChanges. ...

Comparing Input and Output Event Binding

Can you provide reasons why using @Output for events is more advantageous than passing an @Input function in Angular 2+? Utilizing @Input: Parent Template: <my-component [customEventFunction]=myFunction></my-component> Inside parent-compone ...

Troubleshooting problem with TypeScript observables in Angular 5

Having trouble with a messaging app, specifically an error related to TS. The syntax checker in the Editor is flagging this issue: Type 'Observable<{}>' is not compatible with type 'Observable'. Type '{}' cannot be assig ...

I seem to be missing some properties in the request body schema. Why am I receiving an incomplete model for

Seeking assistance in grasping the working of models in loopback4. Here's a model I defined: @model() export class ProductViewConfig extends BaseConfig { @property({ type: 'string', id: true, generated: true, }) _id?: strin ...

The property 'toLowerCase' cannot be accessed as it is undefined or null

Scenario: A textbox is present with a list of data below it. Upon typing in the textbox, the list gets filtered based on the text entered. Code: Pipe: @Pipe({ name: 'search' }) export class SearchPipe implements PipeTransform { transform( ...

The code below is not working as it should be to redirect to the home page after logging in using Angular. Follow these steps to troubleshoot and properly

When looking at this snippet of code: this.router.navigate(['/login'],{queryParams:{returnUrl:state.url}}); An error is displayed stating that "Property 'url' does not exist on type '(name: string, styles: AnimationStyleMetadata". ...

Using Angular Form Builder to assign a value depending on the selected option in a dropdown menu

My approach to Angular Form Builder initialization includes a group that looks like this: contactReason: this.formBuilder.group({ description: '', source: this.sourceType() }) For the 'description' field, I hav ...

Make sure to confirm that 'tables-basic' is an Angular component within the module before proceeding

In my table-basic.component.ts file, I declared 'tables-basic' as a selector and included this template in dashboard.html. Despite following the steps outlined below, I encountered an error which is also highlighted. Snippet from my dashboard.te ...

Angular 4 allows for dynamically applying the active class to a clicked button, enhancing interactivity

Issue: <button *ngFor="let button of buttons" [ngClass]="{'active': isClicked}" (click)="isClicked = !isClicked" Description: A total of 10 buttons are displayed on the screen. When I click on button number 1, each button receives the clas ...

The Angular Compiler was identified, however it turned out to be an incorrect class instance

Although this question has been asked before, I have exhausted all possible solutions that were suggested. Unfortunately, I still cannot resolve it on my own. Any assistance would be greatly appreciated. Error: ERROR in ./src/main.ts Module build failed: ...

Eliminate all citation markers in the final compiled result

Currently, I am consolidating all my .ts files into a single file using the following command: tsc -out app.js app.ts --removeComments This is based on the instructions provided in the npm documentation. However, even after compilation, all reference tag ...

Unlocking the secrets of integrating Vuex store with JavaScript/TypeScript modules: A comprehensive guide

I am working on a vue application and I have a query. How can I access the store from javascript/typescript modules files using import/export? For example, if I create an auth-module that exports state, actions, mutations: export const auth = { namesp ...