1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
---
language: TypeScript
contributors:
- ["Philippe Vlérick", "https://github.com/pvlerick"]
- ["Kiwimoe", "https://github.com/kiwimoe"]
filename: learntypescript.ts
---
TypeScript is a language that aims at easing development of large scale
applications written in JavaScript. TypeScript adds common concepts such as
classes, modules, interfaces, generics and (optional) static typing to
JavaScript. It is a superset of JavaScript: all JavaScript code is valid
TypeScript code so it can be added seamlessly to any project. The TypeScript
compiler emits JavaScript.
This article will focus only on TypeScript extra syntax, as opposed to
[JavaScript](/docs/javascript).
To test TypeScript's compiler, head to the
[Playground](https://www.typescriptlang.org/play) where you will be able
to type code, have auto completion and directly see the emitted JavaScript.
```ts
// There are 3 basic types in TypeScript
let isDone: boolean = false;
let lines: number = 42;
let name: string = "Anders";
// But you can omit the type annotation if the variables are derived
// from explicit literals
let isDone = false;
let lines = 42;
let name = "Anders";
// When it's impossible to know, there is the "Any" type
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
// Use const keyword for constants
const numLivesForCat = 9;
numLivesForCat = 1; // Error
// For collections, there are typed arrays and generic arrays
let list: number[] = [1, 2, 3];
// Alternatively, using the generic array type
let list: Array<number> = [1, 2, 3];
// For enumerations:
enum Color { Red, Green, Blue };
let c: Color = Color.Green;
console.log(Color[c]); // "Green"
// Lastly, "void" is used in the special case of a function returning nothing
function bigHorribleAlert(): void {
alert("I'm a little annoying box!");
}
// Functions are first class citizens, support the lambda "fat arrow" syntax and
// use type inference
// The following are equivalent, the same signature will be inferred by the
// compiler, and same JavaScript will be emitted
let f1 = function (i: number): number { return i * i; }
// Return type inferred
let f2 = function (i: number) { return i * i; }
// "Fat arrow" syntax
let f3 = (i: number): number => { return i * i; }
// "Fat arrow" syntax with return type inferred
let f4 = (i: number) => { return i * i; }
// "Fat arrow" syntax with return type inferred, braceless means no return
// keyword needed
let f5 = (i: number) => i * i;
// Functions can accept more than one type
function f6(i: string | number): void {
console.log("The value was " + i);
}
// Interfaces are structural, anything that has the properties is compliant with
// the interface
interface Person {
name: string;
// Optional properties, marked with a "?"
age?: number;
// And of course functions
move(): void;
}
// Object that implements the "Person" interface
// Can be treated as a Person since it has the name and move properties
let p: Person = { name: "Bobby", move: () => { } };
// Objects that have the optional property:
let validPerson: Person = { name: "Bobby", age: 42, move: () => { } };
// Is not a person because age is not a number
let invalidPerson: Person = { name: "Bobby", age: true };
// Interfaces can also describe a function type
interface SearchFunc {
(source: string, subString: string): boolean;
}
// Only the parameters' types are important, names are not important.
let mySearch: SearchFunc;
mySearch = function (src: string, sub: string) {
return src.search(sub) != -1;
}
// Classes - members are public by default
class Point {
// Properties
x: number;
// Constructor - the public/private keywords in this context will generate
// the boiler plate code for the property and the initialization in the
// constructor.
// In this example, "y" will be defined just like "x" is, but with less code
// Default values are also supported
constructor(x: number, public y: number = 0) {
this.x = x;
}
// Functions
dist(): number { return Math.sqrt(this.x * this.x + this.y * this.y); }
// Static members
static origin = new Point(0, 0);
}
// Classes can be explicitly marked as implementing an interface.
// Any missing properties will then cause an error at compile-time.
class PointPerson implements Person {
name: string
move() {}
}
let p1 = new Point(10, 20);
let p2 = new Point(25); //y will be 0
// Inheritance
class Point3D extends Point {
constructor(x: number, y: number, public z: number = 0) {
super(x, y); // Explicit call to the super class constructor is mandatory
}
// Overwrite
dist(): number {
let d = super.dist();
return Math.sqrt(d * d + this.z * this.z);
}
}
// Modules, "." can be used as separator for sub modules
module Geometry {
export class Square {
constructor(public sideLength: number = 0) {
}
area() {
return Math.pow(this.sideLength, 2);
}
}
}
let s1 = new Geometry.Square(5);
// Local alias for referencing a module
import G = Geometry;
let s2 = new G.Square(10);
// Generics
// Classes
class Tuple<T1, T2> {
constructor(public item1: T1, public item2: T2) {
}
}
// Interfaces
interface Pair<T> {
item1: T;
item2: T;
}
// And functions
let pairToTuple = function <T>(p: Pair<T>) {
return new Tuple(p.item1, p.item2);
};
let tuple = pairToTuple({ item1: "hello", item2: "world" });
// Including references to a definition file:
/// <reference path="jquery.d.ts" />
// Template Strings (strings that use backticks)
// String Interpolation with Template Strings
let name = 'Tyrone';
let greeting = `Hi ${name}, how are you?`
// Multiline Strings with Template Strings
let multiline = `This is an example
of a multiline string`;
// READONLY: New Feature in TypeScript 3.1
interface Person {
readonly name: string;
readonly age: number;
}
var p1: Person = { name: "Tyrone", age: 42 };
p1.age = 25; // Error, p1.age is read-only
var p2 = { name: "John", age: 60 };
var p3: Person = p2; // Ok, read-only alias for p2
p3.age = 35; // Error, p3.age is read-only
p2.age = 45; // Ok, but also changes p3.age because of aliasing
class Car {
readonly make: string;
readonly model: string;
readonly year = 2018;
constructor() {
this.make = "Unknown Make"; // Assignment permitted in constructor
this.model = "Unknown Model"; // Assignment permitted in constructor
}
}
let numbers: Array<number> = [0, 1, 2, 3, 4];
let moreNumbers: ReadonlyArray<number> = numbers;
moreNumbers[5] = 5; // Error, elements are read-only
moreNumbers.push(5); // Error, no push method (because it mutates array)
moreNumbers.length = 3; // Error, length is read-only
numbers = moreNumbers; // Error, mutating methods are missing
// Tagged Union Types for modelling state that can be in one of many shapes
type State =
| { type: "loading" }
| { type: "success", value: number }
| { type: "error", message: string };
declare const state: State;
if (state.type === "success") {
console.log(state.value);
} else if (state.type === "error") {
console.error(state.message);
}
// Template Literal Types
// Use to create complex string types
type OrderSize = "regular" | "large";
type OrderItem = "Espresso" | "Cappuccino";
type Order = `A ${OrderSize} ${OrderItem}`;
let order1: Order = "A regular Cappuccino";
let order2: Order = "A large Espresso";
let order3: Order = "A small Espresso"; // Error
// Iterators and Generators
// for..of statement
// iterate over the list of values on the object being iterated
let arrayOfAnyType = [1, "string", false];
for (const val of arrayOfAnyType) {
console.log(val); // 1, "string", false
}
let list = [4, 5, 6];
for (const i of list) {
console.log(i); // 4, 5, 6
}
// for..in statement
// iterate over the list of keys on the object being iterated
for (const i in list) {
console.log(i); // 0, 1, 2
}
// Type Assertion
let foo = {} // Creating foo as an empty object
foo.bar = 123 // Error: property 'bar' does not exist on `{}`
foo.baz = 'hello world' // Error: property 'baz' does not exist on `{}`
// Because the inferred type of foo is `{}` (an object with 0 properties), you
// are not allowed to add bar and baz to it. However with type assertion,
// the following will pass:
interface Foo {
bar: number;
baz: string;
}
let foo = {} as Foo; // Type assertion here
foo.bar = 123;
foo.baz = 'hello world'
```
## Further Reading
* [Official TypeScript website](https://www.typescriptlang.org/)
* [Source code on GitHub](https://github.com/microsoft/TypeScript)
* [Learn TypeScript](https://learntypescript.dev/)
|