12

I was taking a look at AngularJS 2 and Typescript and I decided to make something with this just to learn the basics of Typescript. With many research I found good topics about modules, Typescript, and one of them was talking about the 'let' and 'var' command to declare variables; according to this question, the Typescript code below should display only one alert and throw an error in the console:

test.ts:

for(let i = 0; i < 1; i++) {
    alert(i);
}
alert(i);

Compiled test.js:

for(var i = 0; i < 1; i++) {
    alert(i);
}
alert(i);
//# sourceMappingURL=test.js.map

But it isn't. The compiler "ignores" the "let" command and turns it into the "var" command. Why does this happen? Does Typescript only works properly with classes?

I'm using AngularJS configuration for 'npm start', so it compiles my 'test.ts' file automatically:

  "scripts": {
    "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "lite": "lite-server",
    "postinstall": "typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings"
  },
Community
  • 1
  • 1
Edie Johnny
  • 513
  • 2
  • 5
  • 14

3 Answers3

23

But it isn't. The compiler "ignores" the "let" command and turns it into the "var" command. Why does this happen? Does Typescript only works properly with classes?

The compiler by default transpiles to ES3. The let keyword doesn't exist in ES3 and so the emitter must emit code using syntax available in ES3... in this case the best replacement for the let keyword is the var keyword.

If you want it to emit with the let keyword, then you must target ES6—"target": "es6" in tsconfig.json or the command line option --target es6. Doing this will output with the same code that you inputted.

Note that even though your code works at runtime, it throws an error to let you know you have made a mistake at compile time:

for(let i = 0; i < 1; i++) {
    alert(i);
}
alert(i); // compile error: cannot find name 'i'
David Sherret
  • 101,669
  • 28
  • 188
  • 178
2

In this example, var and let have the same effect, with var being a little faster on most JS engines, so TypeScript does some performances optimization for you by changing that to a var.

Now if you try a different example, you will see that let isn't just changed into var, but more magic happens:

for (let i = 0; i < 3; i++) {
  setTimeout(function() { alert(i); });
}

Indeed in this example let and var wouldn't have the same effect. let would display 1 2 3 while using var we would see 3 3 3. If you want to learn more about the let keyword introduced by ES6 you can check this:

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/let

floribon
  • 19,175
  • 5
  • 54
  • 66
  • `i < 1` So zero(0)? *Up* that to `i < 5` so people can really see the magic. Maybe offer the same loop using `var` to compare the differences. Just a suggestion. – mferly May 25 '16 at 16:37
  • I think it isn't the same. If I run my example in pure JS, console gives me an error and only one alert is displayed like I expected. If I put it on TS and compile, it show both alerts because it turns the 'let' into 'var'. So I'm not having the same results with the same codes just because TS doesn't accept the 'let' word. – Edie Johnny May 25 '16 at 16:48
  • @Marcus here the number of iterations doesn't change the point: the transpilation is totally different when we leave the stack with setTimeout, even if it's only once. You can see that using https://www.typescriptlang.org/play/ – floribon May 25 '16 at 16:58
  • @EdieJohnny I understand your point now, indeed the transpilation hides an error, you are totally right. I guess the reasonable conclusion is that you should check the code for potential errors with tools such as `jshint` or `eslint` before transpilation, if possible. However I don't use TypeScript myself so I cannot tell more about that, and these tools probably won't even work with it. – floribon May 25 '16 at 17:00
  • @floribon - I get that. My suggestion was only to (possibly) improve your answer for those who might not. Returning an `alert` one time with `0` might leave people wondering what was so special about that. But with my suggested change you can see what is actually happening, ie. `var i = 0; i < 5; $i++) // 5 5 5 5 5, vs. `for (let i = 0; i < 5; i++) // 0 1 2 3 4 No worries though, man. In the end, it doesn't really matter. Cheers. – mferly May 25 '16 at 17:03
  • The reason it does this is not for performance optimizations. That's a [non-goal](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals) of the compiler. – David Sherret May 25 '16 at 17:27
  • @Marcus right that's a good point to educate people about the differences between the 2 words. I chose to keep OP initial example but indeed it would make more sense to actually show the difference with multiple iterations, I'm editing that – floribon May 26 '16 at 09:04
  • @DavidSherret thanks for this precision, as I said I don't know much about TypeScript so was only making an assumption. If it's not for performances then I guess then it's a transpilation into ES5 where `let` is not supported and should always be adapted to a `var`. Feel free to post an answer or edit mine if you want to bring more explanations to the readers. Cheers – floribon May 26 '16 at 09:07
0

They are identical but there is a difference when they used inside a function.

LET

function theDifference(){
    for(let emre = 0; emre < 10; emre++){
    // emre is only visible inside of this for()
    }

// emre is NOT visible here.
}

VAR

function theDifference(){
    for(var emre = 0; emre < 10; emre++){
    // emre is visible inside of this for()
    }

// emre is visible here too.
}
Emre Bolat
  • 4,316
  • 5
  • 29
  • 32
  • This isn't a good example. The Typescript compiler will complain, but `emre` is actually still visible outside of the `for` in the `let` example. – JohnnyHK May 25 '16 at 16:46