What is the reason behind typescript transpiler's decision not to hoist variables?

While ES6 and TypeScript both offer block level scoping, it is worth noting that when targeting ES3 and ES5, the output will default to function level scoping. I find it interesting that TypeScript does not hoist variables and am curious about the reasoning behind this decision.

For instance, consider the following TypeScript code:

function seed(length: number, multiplier: number): number[] {
  let result: number[] = [];

  for(let i: number = 0; i < length; i++) {
    let n: number = i * multiplier;

    result.push(n);
  }

  return result;
}

Upon transpiling, the output would be:

function seed(length, multiplier) {
  var result = [];
  for (var i = 0; i < length; i++) {
    var n = i * multiplier;
    result.push(n);
  }
  return result;
}

I had expected the variable declarations to be hoisted to the top of the function, creating a structure like this:

function seed(length, multiplier) {
  var
    i, n,
    result = [];

  for (i = 0; i < length; i++) {
    n = i * multiplier;
    result.push(n);
  }
  return result;
}

If you have any insights on this behavior, I would greatly appreciate it. Thank you!

Answer №1

The reason for this behavior is that the compiler does not generate code according to a specific coding standard. Instead, it aims to closely resemble the original input provided.

It's worth noting that variables declared with var are hoisted behind the scenes anyways (var hoisting). Therefore, in this scenario, there is no necessity for the TypeScript compiler to modify the input, as doing so would unnecessarily complicate its operation.

Answer №2

It seems that TypeScript has a deliberate logic behind not hoisting variables, presenting more of a curiosity rather than a problem for developers.

Indeed, since it doesn't pose any issue, there's no need to go through the trouble of hoisting.

Additionally, in the case of using let, hoisting as shown would actually be incorrect.

Temporal Dead Zone

One key aspect is that let variables cannot be accessed before declaration like var. Trying to do so with let will result in a ReferenceError due to the "temporal dead zone". Thankfully, TypeScript catches this error at compile time:

console.log(a); // Error: Block scoped variable used before declaration 
let a = 123;

Block Scoping

let variables declared within a for loop are only accessible within that loop, as they are block-scoped rather than function-scoped. Learn more about this here.

Once again, TypeScript provides compile time errors for incorrect usage of let to prevent runtime issues:

for(let i: number = 0; i < 10; i++) {    
}  
console.log(i); // Error: no variable i in scope

I hope this explanation clarifies things 🌹

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

When attempting to publish an index.d.ts file using npm, the module is

We are currently in the process of developing an npm package that will serve as the foundation for most of our projects. However, we have encountered some issues that need to be addressed: The index.d.ts file of our base npm package is structured as shown ...

Deployment of a NextJS14 app to Vercel encountered an issue: Unexpected token '<' found in JSON at position 0

Here is the issue at hand: next: 14.1.4 next-auth: 4.24.7 node version: 20 This is the structure of my authentication folder: No errors occur when running npm run dev I've been investigating this issue for three days, but I am still stuck. I belie ...

What could be the reason for the unavailability of this.state in this particular situation?

In my component, I have defined the following functions: constructor(MyProps: Readonly<MyProps>){ super(MyProps); this.state = {suppliers: [], supplierId:0, supplierName:''}; this.addSupplier.bind(this); } addSupplier(){ ...

TypeScript interfaces do not strictly enforce properties when an object is assigned

Can someone help me understand TypeScript's rules for interfaces better? I am confused about why the following block of code throws an error due to the id property missing from the interface: interface Person { name: string; } let person: Person = ...

Obtain the selected type from a tuple after filtering

I have a tuple with multiple objects stored in it. const repos = [ { name: 'react', type: 'JS' }, { name: 'angular', type: 'TS' }, ] as const const RepoTypes = typeof repos const jsRepoTypes = FilterRepos<&a ...

Confirming the legitimacy of ISO-8061 dates using the Decoder method

When it comes to simplicity, using the Decoder approach with io-ts has proven to be effective: import { isRight } from 'fp-ts/Either'; import * as D from 'io-ts/Decoder'; const thing = D.struct({ id: D.number, createdAt: D.string, ...

Error: `target` property is not recognized on `htmlelement` type

I am attempting to retrieve the ID of a list item in a select menu but I am having trouble getting the value from it. The value should be a number. HTML File <div class="form-group mt-3"> <label class="form-label">Produc ...

Vue: rendering props cannot be utilized with TSX

After switching my setup from JSX in a Vue component to TS with vue-class-component, I found that only the code snippet below works for me (as shown in the example on repo): import Vue from 'vue' import { Component } from 'vue-property-dec ...

Can TestCafe be used to simulate pressing the key combination (Ctrl + +)?

I've been having a tough time trying to use the key combination specified in the title (Ctrl + +). So far, this is what I've attempted: 'ctrl+\+' 'ctrl+\\+' Does TestCafe even support this key combination? T ...

Can you explain the contrast between Angular 2 components and directives?

I have been having difficulty grasping the distinction between these two ideas within the framework. I am quite experienced with directives in AngularJS 1.x, and both components and directives in Angular 2 appear to be closely related to this concept... ...

Struggling to transmit data to material dialog in Angular2+

I am facing an issue with my Material Dialog not working properly. Can anyone point out what I might be missing? product-thumbnail.ts I will use this to trigger the dialog export class ProductThumbnailComponent implements OnInit { @Input() product: Pr ...

Differentiating functions in Typescript through method overloading by inferring the second argument's type based on the first argument's

Looking to implement method overloading in Typescript with stricter type checking for method invocation based on different arguments. I am encountering an error: 'props' is possibly 'undefined'. This is the code that is causing the e ...

A guide on setting a default constructor as a parameter in TypeScript

Through collaboration with a fellow coder on StackOverflow, I have mastered the art of specifying a constructor as an argument to a class: type GenericConstructor<T> = { new(): T; } class MyClass<T> { subclass: T; constructor( SubClas ...

Tips on narrowing down the type of callback event depending on the specific event name

I've been working on implementing an event emitter, and the code is pretty straightforward. Currently, tsc is flagging the event type in eventHandler as 'ErrorEvent' | 'MessageEvent'. This seems to be causing some confusion, and I ...

What steps should I take to successfully compile my Typescript Webpack project without any errors?

Currently, I am attempting to convert only two .js files into .ts files within my webpack node.js project and then compile them (actions.ts and flux.ts). When I execute the command: webpack --progress --colors I encounter the following errors: 'use ...

Ensuring that an interface exclusively contains properties from another interface

If I define an interface like this: interface Client { id: number; email: string; firstName: string; lastName: string; cellNumberFull: string; } Then, how can I create a new interface that includes only the properties from GoClient? interface ...

Unable to fake a fetch request using the 'fetch-mock-jest 1.5.1' library

I am attempting to simulate a fetch call using thefetch-mock-jest library, but the code continues to try accessing the remote address and ultimately fails with the error message FetchError: request to https://some.domain.io/app-config.yaml failed, reason: ...

How Typescript allows variables to act as references to other variables

Imagine having a component with aliases for user data. This approach allows for shorter and cleaner variable names, making the code easier to read: @Component({ selector: 'my-view', templateUrl: './view.component.html', sty ...

Is it possible for us to perform an addition operation on two or more items that belong to the same

I am faced with a challenge involving 3 objects of the same type, each having different values for their properties. My goal is to add them together as illustrated below: Consider this scenario: objA = { data: { SH: { propertyA: 0, propertyB: ...

Error code TS 2322 reported in several HttpClient services following the transition from Angular 5.2 to version 6.0.7

Currently, I am in the midst of updating my project to Angular 6 with TypeScript version 2.7.0. Previously, in Angular 5.2.12, my service methods were written like this: isPartDraft = (part: number): Observable<boolean> => this._http.get(`${thi ...