JavaScript has been around a long time; I first encountered it in 2000 when I was working for a web startup. Back in that era of Netscape and Internet Explorer (and testing to make sure your website worked perfectly with the different browsers), JavaScript was most useful for checking input and doing tricks with cursors—it took a few more years for Google to bring out Gmail and Google Maps and showed what JavaScript was really capable of.
To get performance and reliability out of large JavaScript apps requires a lot of resources. Microsoft, Facebook and Google each had to develop their own JavaScript compilers to add static checks. That resource burden led Anders Hejlsberg, who had previously created Turbo Pascal while at Borland and then became the lead architect of C# at Microsoft, to create TypeScript.
TypeScript is one of several programming languages, along with Dart and CoffeeScript, that tried to improve on JavaScript. Dart didn't succeed due to politics but eventually gained a second chance powering Flutter; CoffeeScript, sadly, is on the way out. But TypeScript remains beloved by developers.
ECMAScript and JavaScript
There are lots of terms in the JavaScript ecosystem, some of them confusing—for example, ES5, ES6, and ECMAScript. The lattermost is the language specification behind non-JavaScript programming languages such as ActionScript 3 (which was the programming part of Flash).
JavaScript is an implementation of ECMAScript 5 (aka ES5); by 2013, all browsers supported it. You can check what versions are supported on the CanIUse website (for example, ES6 was supported by 2017). The W3Schools website shows what the individual versions support, all the way up to JS 2021/2022.
The JavaScript engines in browsers can't understand programs written in TypeScript. To run them, the TypeScript transpiler must convert (transpile) TypeScript code into ES5-compatible JavaScript (and you’re not limited to ES5; just specify a different target like ES6). Libraries are provided for each of the other targets, such as ES2016, ES2017, and so on.
Why use TypeScript?
Like it or love it, JavaScript has become ubiquitous. However, many developers feel like they must wrestle with its various issues to get anything done, especially in terms of large-scale projects. For instance, there are multiple ways to construct objects, odd scoping rules, and a particular bugbear: equality. Now some of this (e.g., scoping) improved by ES6—but a study (PDF) in 2017 estimated that 15 percent of bugs in public repository JavaScript code would have been fixed by using a type system such as TypeScript.
What exactly is TypeScript?
TypeScript is a superset of JavaScript that supports interfaces, JavaScript libraries and API documents. You can move any working JavaScript to TypeScript and it will still work. It is possible to take existing JavaScript code, incorporate popular JavaScript libraries, and call TypeScript-generated code from other JavaScript sources. TypeScript never changes the runtime behaviour of JavaScript.
It’s not just a nicer JavaScript but a much-improved version. JavaScript uses object prototypes, which are non-OOP objects that can be created by cloning; with TypeScript, you have the more traditional objects and classes. These are based on the classes and objects introduced in the ES6 specification.
A classic JavaScript “feature” is this equality comparison below. You shouldn't use == because it behaves oddly. The better way is to use ===, which compares values as well as the data types.
if ("" == 0) {
// Should not be equal but they are…
}
In TypeScript, this produces a "This comparison appears to be unintentional because the types 'string' and 'number' have no overlap." error.
Static Typing
Like C#, Java and others, TypeScript provides static typing. JavaScript is a dynamic language so variables can hold any type of data. The TypeScript compiler can catch a lot of bugs at compile time that only show up in JavaScript at runtime especially when you are using variables incorrectly.
In the function add below, the parameters left, right and the return result have the type number:
function add(left: number, right: number): number {
return left + right;
}
The compiler checks that left and right are compatible. If they aren’t, you get an error message. If this was in JavaScript without the types, you’d get funny results.
Even better, TypeScript lets you use generics in functions, types, classes and interfaces. The type is defined by the caller; you can write code like this:
function fred<Type>(arg: Type): Type {
return arg;
}
Let value = fred(“Dice”);
The TypeScript compiler infers the type of “Dice.”
Conclusion
Bugs in JavaScript show themselves only when you run the apps. TypeScript finds them before you run your apps. For small applications, JavaScript is fine… but for anything beyond that, consider writing it in TypeScript.