8

Typescript does not give a compiler error for the following code:

var b = a + 10; // Why no compilation error here

var a = 10;

alert(b.toString());

I would expect the first line to be an error as I have not declared or initialized var a till this time.

If I remove the second line I get the compiler error.

I know its valid in JavaScript but I would expect TypeScript to give me compilation error or warning.

Amitabh
  • 59,111
  • 42
  • 110
  • 159
  • 2
    Because variable declarations are hoisted? – Bergi Jun 24 '13 at 11:04
  • I have explained why TypeScript *has to* allow it. It is because you might need to do `var x = undefined` – basarat Jun 24 '13 at 11:58
  • And In C# an unassigned variable has no meaning. In JavaScript it does. So TypeScript has to allow this. – basarat Jun 24 '13 at 11:59
  • I've shown you cases where you actually *need* this "stupid thing". E.g the module pattern. It would be bad if TypeScript took that power of JavaScript away! – basarat Jun 24 '13 at 21:06

2 Answers2

11

Because hoisting behavior can be confusing. Your code actually means.

var a, b

b = a + 10
a = 10

alert(b.toString())

There are valid reasons to allow hoisting, but they don't involve var, but function - you can call function declared later.

alert(identity(i))

function identity(i) {
    return i
}

In this case, alert uses result of function declared later. Thanks to hoisting behavior, it works.

While I agree this case should have an warning (not error, TypeScript wants to be compatible with JavaScript), it doesn't appear that TypeScript currently notices that. Every variable in TypeScript has a type that CANNOT change during lifetime of variable, and in your case, a is number type (it isn't aware that you use it before assignment, because var sets type implicitly). TypeScript assumes it's a number, even if it's not, because of its declaration.

You may want to report this as a bug in TypeScript.

Community
  • 1
  • 1
Konrad Borowski
  • 11,584
  • 3
  • 57
  • 71
  • Its not protecting me. It is allowing me to do that. Which I dont want. – Amitabh Jun 24 '13 at 11:06
  • 1
    I'm not so sure about your function example. While it's obvious that `a` references `b`, the body of function is not evaluated until `a` is called. So, this does not have anything to do with hoisting IMO. Here is an example of what I mean: http://jsfiddle.net/fJ9RV/. Although `foo` does not exist at the time of definition and it is not hoisted (because there is no variable declaration), no error is thrown, as long as you call `b` before `a`. – Felix Kling Jun 24 '13 at 11:43
6

Assuming you understand that your code is equivalent to:

var a, b
b = a + 10
a = 10
alert(b.toString())

Which in turn is equivalent to:

var a = undefined, b = undefined
b = a + 10
a = 10
alert(b.toString())

The reason why it should be allowed is because undefined is a valid value for a variable that you can assign and read.

There are various use cases where this functionality is valuable. E.g The module pattern used in typescript:

module x{
    export var foo; 
}

Generates javascript code that exploits this fact:

var x;
(function (x) {
    x.foo;
})(x || (x = {})); //x was never assigned but used in "x ||" part

This is left in TypeScript due to JavaScript backward compatibility (not to mention it is useful).

Here is a purely TypeScript usecase. Perhaps you want to pass undefined into a function call (this is valid typescript):

var a:number = undefined; // same as simply "var a" 
console.log(a);

It is just assumed that the TypeScript developer wants the power of the underlying JavaScript language.

This is not the case for languages where Reading before Assignment is invalid (e.g C#). In C# an unassigned variable has no meaning. In JavaScript it does. So TypeScript has to allow this.

basarat
  • 261,912
  • 58
  • 460
  • 511