Why TypeScript
There are two main goals of TypeScript:
- Provide an optional type system for JavaScript.
- Provide planned features from future JavaScript editions to current JavaScript engines
The desire for these goals is motivated below.
The TypeScript type system
You might be wondering “Why add types to JavaScript?“
Types have proven ability to enhance code quality and understandability. Large teams (Google, Microsoft, Facebook) have continually arrived at this conclusion. Specifically:
- Types increase your agility when doing refactoring. It’s better for the compiler to catch errors than to have things fail at runtime.
- Types are one of the best forms of documentation you can have. The function signature is a theorem and the function body is the proof.
However types have a way of being unnecessarily ceremonious. TypeScript is very particular about keeping the barrier to entry as low as possible. Here’s how:
Your JavaScript is TypeScript
TypeScript provides compile time type safety for your JavaScript code. This is no surprise given its name. The great thing is that the types are completely optional. Your JavaScript code .js
file can be renamed to a .ts
file and TypeScript will still give you back valid .js
equivalent to the original JavaScript file. TypeScript is intentionally and strictly a superset of JavaScript with optional Type checking.
Types can be Implicit
TypeScript will try to infer as much of the type information as it can in order to give you type safety with minimal cost of productivity during code development. For example, in the following example TypeScript will know that foo is of type number
below and will give an error on the second line as shown:
var foo = 123;
foo = '456'; // Error: cannot assign `string` to `number`
// Is foo a number or a string?
This type inference is well motivated. If you do stuff like shown in this example, then, in the rest of your code, you cannot be certain that foo
is a number
or a string
. Such issues turn up often in large multi-file code bases. We will deep dive into the type inference rules later.
Types can be Explicit
As we’ve mentioned before, TypeScript will infer as much as it can safely, however you can use annotations to:
- Help along the compiler, and more importantly document stuff for the next developer who has to read your code (that might be future you!).
- Enforce that what the compiler sees, is what you thought it should see. That is your understanding of the code matches an algorithmic analysis of the code (done by the compiler).
TypeScript uses postfix type annotations popular in other optionally annotated languages (e.g. ActionScript and F#).
var foo: number = 123;
So if you do something wrong the compiler will error e.g.:
var foo: number = '123'; // Error: cannot assign a `string` to a `number`
We will discuss all the details of all the annotation syntax supported by TypeScript in a later chapter.
Types are structural
In some languages (specifically nominally typed ones) static typing results in unnecessary ceremony because even though you know that the code will work fine the language semantics force you to copy stuff around. This is why stuff like automapper for C# is vital for C#. In TypeScript because we really want it to be easy for JavaScript developers with a minimum cognitive overload, types are structural. This means that duck typing is a first class language construct. Consider the following example. The function iTakePoint2D
will accept anything that contains all the things (x
and y
) it expects:
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
var point2D: Point2D = { x: 0, y: 10 }
var point3D: Point3D = { x: 0, y: 10, z: 20 }
function iTakePoint2D(point: Point2D) { /* do something */ }
iTakePoint2D(point2D); // exact match okay
iTakePoint2D(point3D); // extra information okay
iTakePoint2D({ x: 0 }); // Error: missing information `y`
Type errors do not prevent JavaScript emit
To make it easy for you to migrate your JavaScript code to TypeScript, even if there are compilation errors, by default TypeScript will emit valid JavaScript the best that it can. e.g.
var foo = 123;
foo = '456'; // Error: cannot assign a `string` to a `number`
will emit the following js:
var foo = 123;
foo = '456';
So you can incrementally upgrade your JavaScript code to TypeScript. This is very different from how many other language compilers work and yet another reason to move to TypeScript.
Types can be ambient
A major design goal of TypeScript was to make it possible for you to safely and easily use existing JavaScript libraries in TypeScript. TypeScript does this by means of declaration. TypeScript provides you with a sliding scale of how much or how little effort you want to put in your declarations, the more effort you put the more type safety + code intelligence you get. Note that definitions for most of the popular JavaScript libraries have already been written for you by the DefinitelyTyped community so for most purposes either:
- The definition file already exists.
- Or at the very least, you have a vast list of well reviewed TypeScript declaration templates already available
As a quick example of how you would author your own declaration file, consider a trivial example of jquery. By default (as is to be expected of good JS code) TypeScript expects you to declare (i.e. use var
somewhere) before you use a variable
$('.awesome').show(); // Error: cannot find name `$`
As a quick fix you can tell TypeScript that there is indeed something called $
:
declare var $: any;
$('.awesome').show(); // Okay!
If you want you can build on this basic definition and provide more information to help protect you from errors:
declare var $: {
(selector:string): any;
};
$('.awesome').show(); // Okay!
$(123).show(); // Error: selector needs to be a string
We will discuss the details of creating TypeScript definitions for existing JavaScript in detail later once you know more about TypeScript (e.g. stuff like interface
and the any
).
Future JavaScript => Now
TypeScript provides a number of features that are planned in ES6 for current JavaScript engines (that only support ES5 etc). The typescript team is actively adding these features and this list is only going to get bigger over time and we will cover this in its own section. But just as a specimen here is an example of a class:
class Point {
constructor(public x: number, public y: number) {
}
add(point: Point) {
return new Point(this.x + point.x, this.y + point.y);
}
}
var p1 = new Point(0, 10);
var p2 = new Point(10, 20);
var p3 = p1.add(p2); // { x: 10, y: 30 }
and the lovely fat arrow function:
var inc = x => x+1;
Summary
In this section we have provided you with the motivation and design goals of TypeScript. With this out of the way we can dig into the nitty gritty details of TypeScript.