46

I just started using TypeScript and sometimes get compiler errors "use of undeclared variable". For example the following works in plain JavaScript :

var foo = {};
foo.bar = 42;

If I try to do the same in TypeScript it won't work and give me the mentioned error above. I have to write it like that:

var foo :any = {};
foo.bar = 42;

In plain JavaScript the type definition with any is neither required nor valid, but in TypeScript this seems to be mandatory. I understand the error and the reason for it, but I always heard in Videos and read in the documentation:

typescriptlang.org:

"TypeScript is a typed superset of JavaScript [...]"

Introduction Video @minute 3:20:

"All JavaScript code is TypeScript code, simply copy and paste"

Is that a thing that changed during the development of TypeScript or do I have to pass a specific compiler setting to make this work?

OschtärEi
  • 2,255
  • 3
  • 20
  • 41
Markus
  • 3,225
  • 6
  • 35
  • 47
  • 2
    It is a superset. But this doesn't mean that it can be 1) compiled and 2) used as regular JavaScript. Objective-C is superset of C/++, but it goes with its own compiler/IDE/environment. You must follow TypeScript directives and not compare it that literally to JavaScript. – Andrey Popov Apr 28 '15 at 11:37
  • 3
    Hmm, maybe this is just bad wording. It's not really an *error* is it? More a *warning* because it does generate valid Javascript. Certainly TypeScript often touts that giving Javascript to the compiler should *"just work"* – CodingIntrigue Apr 28 '15 at 11:54
  • 1
    @AndreyPopov: Ok but than it is not a syntactic super set of JavaScript and in particular the second quote is flat wrong ... – Markus Apr 28 '15 at 11:55
  • 1
    A language being a syntactic sub/superset and complying with all of a compiler's guidelines and error checks are two different things really. I don't know, but probably you could disable those warnings in the compiler and it would compile just fine?! – deceze Apr 28 '15 at 11:56
  • 1
    @deceze It actually compiles fine as is. `tsc thatCode.ts` creates `thatCode.js` with valid JS – CodingIntrigue Apr 28 '15 at 11:56
  • 2
    @RGraham There you go, so the languages are syntactically compatible just fine. – deceze Apr 28 '15 at 11:57
  • @RGraham: I think you are right - it is just Visual Studio or a plugin (WebEssentials / ReSharper) that is returning it as an error in the 'Error List' window. – Markus Apr 28 '15 at 11:58
  • 2
    `error TS2094: The property 'bar' does not exist on value of type '{}'.` is literally what `tsc` responds with. But it's not an error and if it is, it's certainly not a critical one :) Good question though. TypeScript always seems simple at first glance, but it's got just as many quirks as JS – CodingIntrigue Apr 28 '15 at 12:01
  • 2
    When I read "error TS2094", then in my world this is an **error** ... this means that the TypeScript is not valid, even though the compiler might emit working JavaScript ... – jbandi Oct 01 '16 at 19:34
  • See [What does "all legal JavaScript is legal TypeScript" mean?](https://stackoverflow.com/questions/41750390/what-does-all-legal-javascript-is-legal-typescript-mean) – Bergi Aug 18 '23 at 22:56

4 Answers4

36

The reason for TypeScript's existence is to have a compiler and language which can enforce types better than vanilla Javascript does. Any regular Javascript is valid TypeScript, syntactically. That does not mean that the compiler must be entirely happy with it. Vanilla Javascript often contains code which is problematic in terms of type security. That doesn't make it invalid TypeScript code, but it's exactly the reason why TypeScript exists and it's exactly the compiler's job to point out those problems to you.

The languages as such are still sub/supersets of one another.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • 2
    You put into words what I felt and couldn't really find the right words to describe. The TypeScript code does compile and produces JavaScript output – Ruan Mendes Apr 28 '15 at 12:09
  • 12
    If the TypeScript compiler throws an error, I would argue that the code is not valid TypeScript, even though the compiler might still emit working JavaScript. As a consequence I would argue that technically TypeScript is **not** a superset of JavaScript. Which does in no way diminish the value of TypeScript, since this is exactly the goal of TypeScript: To constrain the "dynamic" parts of JavaScript. – jbandi Oct 01 '16 at 19:31
  • 2
    @jbandi: Yep, and that is exactly the problem. You can't just copy JavaScript and rename to TypeScript, and then add types. You usually need to fix a lot of issues. And there are valid JavaScript expressions, that are impossible to produce in TypeScript, e.g. accessing the raw this-context in a arrow-function. Or accessing a instance variable without "this". Thus, TypeScript is technically both a super & subset of javascript. A subsupperset, so to say. They have a lot of intersection, but JavaScript isn't entirely contained within TypeScript. And that's the problem. – Stefan Steiger Apr 10 '18 at 04:41
  • 1
    @StefanSteiger you mean _neither_ a superset _nor_ a subset. TS is not a supserset of JS because some JS code is not valid TS code (even though most JS code is). TS is not a subset of JS because some TS code is not valid JS code (ex. type annotations). When people say one language is a subset of another, they are referring to valid code in that language, not the code produced by that language's compiler. The code generated by TS compiler is a subset of JS because all code generated by the TS compiler is valid JS (except for bugs in the TS compiler ;-). – charmoniumQ Dec 10 '18 at 01:49
  • 2
    @deceze Considering _syntactic_ validity of the language is uncommon and probably not what the OP intends. If that were the case, then `int x = "hello world";` would be valid C because it parses properly and merely has a type-error. When the TS compiler emits an error and still compiles the code, the compilation is not 'sucessful' and the resulting code may not run as expected. Even if you accept this definition, TS is not a subset of JS as stated in the answer; it is a superset (there is valid TS that is not valid JS). – charmoniumQ Dec 10 '18 at 02:07
  • 2
    Whether you consider it still a "superset" doesn't matter to anyone if you can't compile the same code in TS. People have told me that all JS code works in TypeScript and that I can just copy-paste it, which is false. That actually matters because copy-pasting code is nice. And anyway, yeah, most people would expect that "superset" means all JS code compiles in TS. – sudo Apr 10 '19 at 01:37
  • The distinction between syntactic & semantic validity is immaterial, IMHO. The only one that cares about that is the parser itself. For the language users it makes much more sense to think of a "valid program in language A" as a syntactically *and* well typed program in that language. In this sense, which I argue is what people use in everyday usage, TypeScript is definitely **not** a superset of JS, they just happen to have some programs in common. – Giacomo Alzetta Sep 24 '19 at 12:19
  • 1
    Yeah I mean the code is useless to me if it doesn't run. – sudo Mar 26 '21 at 06:48
28

Theorem: TypeScript is neither a subset nor a superset of JavaScript.

Proof:

When we say language A is a subset of language B, we mean all valid A-programs are also valid B-programs.

Here is a valid TypeScript program that is not a valid JavaScript program:

let x: number = 3;

You identified a valid JavaScript program that is not a valid TypeScript program:

var foo = {};
foo.bar = 42;

Complicating factor 1: TypeScript is almost a superset. TypeScript is intended to be a near superset of JavaScript. Most valid JS is also valid TS. What JS is not can usually be easily tweaked to compile without errors in TS. In other words, most valid JS is also valid TS.

Complicating factor 2: non-fatal errors The TypeScript compiler generates the JavaScript code you intend sometimes even if there are errors. The your example that I referenced earlier emits this error

error TS2339: Property 'bar' does not exist on type '{}'.

but also this JS code

var foo = {};
foo.bar = 42;

The TS documentation notes

You can use TypeScript even if there are errors in your code. But in this case, TypeScript is warning that your code will likely not run as expected.

I think we can call this a failed compilation (and thus invalid TypeScript) for the following reasons:

  1. The compiler seems to use the term warning in the conventional sense, so we should interpret error in the conventional sense too: an error indicates the compilation failed.
  2. The documentation indicates that the resulting JavaScript is not necessarily correct as to what was intended. An incorrect output seems just as bad as (if not worse than) no output. They should both be considered failed.
  3. The TypeScript compiler exits with a non-zero status code, which conventionally indicates that the process failed in some way.
  4. If we call any TypeScript program that outputs JavaScript "valid", then we would have to call the following TypeScript program valid, because it a dot compiles to the empty string after issuing errors:
.

Complicating factor 3: TS accepts JS files: The TypeScript compiler can passthrough files ending in .js (see compiler documentation for --allowJs). In this sense TypeScript is a superset of JS. All .js files can be compiled with TypeScript. This is probably not what people who visit this question are meaning to ask.

I think complicating factor 1 is the thing that Anders Hejlsberg is getting at. It might also justify the misleading marketing on TypeScript's homepage. The other answers have fallen prey to complicating factor 2. However the general advice given in the other answers is correct: TypeScript is a layer on top of JavaScript designed to tell you when you do something bad. They are different tools for different purposes.

charmoniumQ
  • 5,214
  • 5
  • 33
  • 51
  • 1
    I'd argue that if the typescript compiler emits Javascript that matches the intent and functionality of the input Javascript, it succeeds. If TS were not a superset of JS, there would be valid JS programs that, after TS compilation, no longer function as they did before. – fwip Aug 09 '21 at 21:33
  • 1
    This! If Typescript were a superset of Javascript, then all valid Javascript programs would also be valid Typescript programs by definition. It's a misuse of the term "superset". – Tony Andrews Sep 09 '21 at 08:31
11

No. In other answers I believe the technical reason has been well explained, but I notice an example that could immediately serve as a contradiction to the claim in the question (different semantics):

// In TypeScript
function f<A>(a: A) { return a; };

console.log(f<Function>(f)); // <-- This line. It will print the function f since it is an identify function that in this case takes self and returns self.

Comparing to the below JavaScript example

// In JavaScript
function f(a) { return a; };

console.log(f<Function>(f)); // <-- This line. This is VALID JavaScript

At first glance you might think there should be a syntax error for the JavaScript example. HOWEVER, once you examine it closely, you'll notice that actually the line is executed as

console.log((f < Function) > f); // Evaluate to false

which is completely valid in JavaScript. This essentially means the same line of code resulted in 2 completely different interpretation in JavaScript and TypeScript, therefore a counterexample to the question.

Kevin Qian
  • 2,532
  • 1
  • 16
  • 26
6

The definition

"All JavaScript code is TypeScript code, simply copy and paste"

is true. Because any JavaScript code can passed to the TypeScript compiler.

So it's sort of a Layer on top of JavaScript. So, of course the underlaying Layer (JavaScript) can be passed through the layers to the top (TypeScript), but not the other way around.

Why not?

Think of it as a bike (JavaScript) and a motorcycle (TypeScript). The basics are the same (two wheels, a frame), but the motorcycle as an engine and some enhanced features.

So, you can use your motorcycle (TypeScript) as a bike (JavaScript), but you cannot use a bike as a motorcycle.

EDIT:

If your compiler throws a warning, why does it make the statement wrong? It just says: Hey, you are using TypeScript, and it's more strict than what you gave me.

See this example, it compiles perfectly to JavaScript, but throws a warning.

ohboy21
  • 4,259
  • 8
  • 38
  • 66
  • 6
    If you can pass any JS code to TypeScript compiler, why does valid JavaScript (`var foo={}; foo.bar = 42;`) throw an error/warning? – JJJ Apr 28 '15 at 11:47
  • You are writing plain JavaScript in a .ts file. You try to use a motor engine with your plain bike. A .js file gets "compiled" perfectly. – ohboy21 Apr 28 '15 at 11:54
  • 5
    @gruberb But the point is that it *doesn't*. See the OP have given valid JS and it throws an error - I missed this too first time around – CodingIntrigue Apr 28 '15 at 11:55
  • 5
    A clear example where valid JS code is not valid TS code is given in question. You should explain more if you think it's true instead of talking about motorcycles and the other way. – Džuris Apr 28 '15 at 11:57
  • @Juris Just click the link. The outcome is pure JavaScript, which makes it correct. Just because the compiler says: Hey, please don't better do this, doesn't make this wrong. – ohboy21 Apr 28 '15 at 12:00
  • 3
    If the TypeScript compiler throws an error, I would argue that the code is not *valid* TypeScript, even though the compiler might still emit working JavaScript. If the definition of the "superset" is that any *valid* JavaScript is also *valid* TypeScript, then TypeScript is **not** a superset of JavaScript. – jbandi Oct 01 '16 at 19:26
  • 3
    “ So, you can use your motorcycle (TypeScript) as a bike (JavaScript), but you cannot use a bike as a motorcycle.” This is exactly backwards. You cannot use a motor cycle as a bike unless you have a motorcycle with... pedals? You can put motors on bicycles; they’re called mopeds, and they rock. Just like JS, which rocks so hard. – Wesley Robinson Nov 26 '19 at 04:33
  • 1
    The compiler doesn't just say "please don't do this." It doesn't let me run my code. – sudo Mar 26 '21 at 06:50