Web
Typescript
## Overview of Today's Class - Retour évaluation du cours - What is Typescript? - Typescript types - Type aliasing - Type unions - Type assertions - Functions - Generics
What is Typescript?
## Typescript Typescript is - a static type checker for JavaScript, - a superset of JavaScript (i.e. JS is TS, but TS is not JS), - a language that compiles to JavaScript
https://www.typescriptlang.org/
## Compiling Typescript **Source-to-source compilation** : `tsc` compiles typescript to JavaScript. ```bash npm install -g typescript tsc hello.ts ``` - Compilation does type checking and removes type annotations. - Can target older versions of JS (e.g. ES5 with `--target es2015`). - By default, targets ES3. - Flags can control how strict the compiler is.
## Exploring Typescript - [Typescript playground](https://www.typescriptlang.org/play/) - [Solving Typescript Errors](https://www.totaltypescript.com/tutorials/solving-typescript-errors/errors/fixing-x-is-not-assignable-to-y/exercise) - [Typescript Exercises](https://typescript-exercises.github.io/#exercise=4&file=%2Findex.ts)
Typescript types
## Primitive types - `number` - `string` - `boolean` - `null` - `undefined` We will see about `null` and `undefined` values later; they are special.
## Type annotation Typescript can infer types from the code, but it is better to annotate them explicitly. ```typescript let x = 42; // x is inferred to be of type number let y: number = 42; // y is explicitly of type number let z: number; // z is explicitly of type number x = 42; // OK // x = "42"; // Error ``` Function arguments and return values can also be inferred or annotated. ```typescript window.onmousedown = function (mouseEvent) { // Type of mouseEvent inferred to match type of onmousedown }; function add(x: number, y: number): number { /* ... */ } ```
## Object types The type of an object is the set of its properties and their types. ```typescript let obj: { name: string, age: number } = { name: "John", age: 42 }; ``` Any object with those properties and types is of this type. ```typescript let obj = { name: "John", age: 42 }; let obj2 = { name: "John", age: 42, city: "Paris" }; // Both are of type { name: string, age: number } let obj3: { name: string, age: number } = { name: "John", age: "42"}; // Error: age is not a number ``` Typescript uses a structural type system, i.e. two objects are of the same type if they have the same structure.
## Any type `any` is a special "root" type that can be any value. ```typescript let x: any; x = 42; // OK x = "42"; // OK x = { name: "John", age: 42 }; // OK ```
## Null and undefined `null` and `undefined` are special. With `--strictNullChecks`, they are only assignable to themselves and `any`. ```typescript let x: number; x = null; // Error let y: any; y = null; // OK let z: null; z = null; // OK ``` Without `--strictNullChecks`, they are assignable to anything, like in JS. ```typescript let x: number; x = null; // OK ```
## Litteral types (wat?!) Types can be litterals in Typescript. ```typescript let x: 42; x = 42; // OK x = 43; // Error ``` Why?! We'll see...
## Function types The type of a function is the type of its parameters and its return value. ```typescript function add(x: number, y: number): number { return x + y; } // Type : (x: number, y: number) => number ``` Note : the argument names are only for documentation purposes. ```typescript let add: (x: number, y: number) => number; add = function (a: number, b: number): number { return a + b; } // OK, even though argument names don't match ```
## Never type `never` is the type of values that never occur. For example, a function that never returns. ```typescript function error(message: string): never { throw new Error(message); } ```
## `void` type `void` is the type of functions that return nothing. ```typescript function log(message: string): void { console.log(message); } ```
## Array type Arrays are generic types. We will see generics later. In Typescript, all elements of an array must have the same type. ```typescript let x: number[]; // Shorthand notation let y: Array
; // Explicit generics notation x = [1, 2, 3]; // OK x = [1, 2, "3"]; // Error x = ["1", "2", "3"]; // Error ```
## Tuple type A tuple is an array with a fixed number of elements of potentially different types. ```typescript let x: [string, number]; x = ["John", 42]; // OK x = [42, "John"]; // Error ```
Type aliasing
## Type aliasing Types can be aliased with the `type` keyword. ```typescript type Uid = string; type Person = { id: Uid, name: string, age: number }; let john: Person; john = { Uid: "490028839", name: "John", age: 42 }; // OK ```
## Interfaces Interfaces are a special kind of type alias for objects. ```typescript interface Point { x: number; y: number; }; ``` One difference is that more properties can be added later on. ```typescript interface Point { z: number; } // Point now has 3 properties : x, y, z ``` Another difference is that interfaces can be extended. ```typescript interface Point3D extends Point { z: number }; // Point3D has 3 properties : x, y, z ```
Type unions
## Unions In language theory, a union type is the type of a value that can be of several types. ```typescript let x: string | number; x = "John"; // OK x = 42; // OK x = true; // Error ``` Why? ```typescript type Uid = string | number; type LockState = "locked" | "unlocked"; type PositiveOddNumberUnderTen = 1 | 3 | 5 | 7 | 9; function printDouble(x: number | string) { console.log(x + x); } ```
(Hence the relevence of litteral types)
## Narrowing Typescript can understand some `if` statements to narrow the type of a variable. ```typescript function printId(id: number | string) { if (typeof id === "number") { // id has type number in this branch console.log(id); } else { // id has type string in this branch console.log(id.toUpperCase()); // OK because id is a string in this branch } } ```
## Narrowing with the `in` operator Another way to narrow a type is depending on the presence of a property. ```typescript type Fish = { swim: () => void }; type Bird = { fly: () => void }; type Human = { walk: () => void; swim: () => void }; type Animal = Fish | Bird | Human; function move(animal: Animal) { if ("swim" in animal) { // animal has type Fish | Human in this branch return animal.swim(); } return animal.fly(); } ```
Type assertions
## The `as` keyword Typescript can't always infer the type of a variable. We can explicitly tell it what the type is with the `as` keyword. ```typescript // getElementById returns HTMLElement | null; we know it's not null and a canvas element // We thus narrow the union, and type-assert down const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement; ``` We can also type-assert up (i.e. tell Typescript that a variable is of a more general type). However, we may not type-assert to an impossible type. ```typescript let x = "hello" as number; // Error ```
## Non-null assertions If a value's type is a union with `null` and/or `undefined`, we can tell Typescript that the value is not null or undefined. ```typescript function liveDangerously(x?: number | null) { // Pretend x is a number: console.log(x!.toFixed()); // Equivalent to: // console.log((x as number).toFixed()); } ```
## Type assertions are static Type assertions only tell the compiler what type a value has. The compiler will then use that type to type-check the code. **Recall**: because Typescript is only a static type checker, type assertions are removed during compile time and have no effect at runtime.
Functions
## Generic functions Functions can have type parameters. ```typescript function firstElement
(arr: Type[]): Type | undefined { return arr[0]; } ``` They can be constrained in many ways. One example: ```typescript function longest
(a: Type, b: Type) { if (a.length >= b.length) { return a; } else { return b; } } ```
## Optional arguments We can make arguments optional by adding a `?` after their name. They must come after all required arguments. ```typescript function f(x?: number) { // x actually has type number | undefined // ... } f(); // OK, x is undefined f(10); // OK ``` Otherwise, a default value can be given in addition to that argument's type. ```typescript function f(x: number = 10) { // x has type number // ... } ```
## Function overloading Typescript allows multiple functions with the same name but different signatures. ```typescript function makeDate(timestamp: number): Date; // Overload 1 function makeDate(m: number, d: number, y: number): Date; // Overload 2 function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { // Implementation // Arguments are union types of the corresponding arguments in the overloads if (d !== undefined && y !== undefined) { return new Date(y, mOrTimestamp, d); } else { return new Date(mOrTimestamp); } } ``` They are defined as follows. - A list of overloaded signatures, each with different arguments and return type. - A single implementation signature, with each argument being a union of the corresponding arguments in the overloaded signatures. - The function implementation, using the implementation signature's arguments.
Generics
## Generics ```typescript interface BinaryTree
{ value: T; left: BinaryTree
; right: BinaryTree
; getSmallest(): T; } let a: BinaryTree
; ```
Hands on!
## Get used to Typescript Do the first few exercises of [Typescript exercises](https://typescript-exercises.github.io/#exercise=1&file=%2Findex.ts). Go through the questions of [w3schools' quiz](https://www.w3schools.com/typescript/exercise.php?filename=exercise_simple_types2).