31
TypeScript 1.8 All you ever wanted to know by Adrián Caballero July 2016

TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Embed Size (px)

Citation preview

Page 1: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

TypeScript 1.8

All you ever wanted to know by Adrián Caballero

July 2016

Page 2: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Watch the full video of the presentation at:

https://goo.gl/RD7jmr

Page 3: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

TypeScriptTM is a typed object-oriented superset of JavaScript that transcompiles to plain JavaScript.

3

Page 4: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Installation and use

4

$ npm install -g typescript

function greeter(person) { return "Hello, " + person;}

var user = "Jane User";

document.body.innerHTML = greeter(user);

function greeter(person) { return "Hello, " + person;}

var user = "Jane User";

document.body.innerHTML = greeter(user);

// greeter.ts // greeter.js

tsc greeter.ts

Page 5: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Basic types & Type annotations (I)

Boolean

String & template strings (`)

5

let isDone: boolean = false;

let decimal: number = 6;let hex: number = 0xf00d;let binary: number = 0b1010;let octal: number = 0o744;

Number

let color: string = 'blue';color = 'red';

let sentence: string = `Hello world!

Today the sky is ${color}.`

let list: number[] = [1, 2, 3];let list: Array<number> = [1, 2, 3];

let x: [string, number];x = ["hello", 10]; // OKx = [10, "hello"]; // Error

Enum

Tuple

Array

enum Color {Red, Green, Blue};let c: Color = Color.Green;// enum Color {Red = 1, Green, Blue};// enum Color {Red = 1, Green = 3, Blue = 5};

Page 6: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

You can only assign ‘undefined’ or ‘null’

to a ‘void’ variable...

Basic types & Type annotations (II)

Object

6

let notSure: Object = 4;notSure = "maybe a string instead";notSure = false; // okay, definitely a booleannotSure.toFixed(); // compiler error!

let notSure: any = 4;notSure = "maybe a string instead";notSure = false; // okay, definitely a booleannotSure.toFixed(); // compiler doesn’t check

Any

function warnUser(): void { alert("This is my warning message");}

Void

Type assertionslet a: any = "this is a string";

let strLength1: number = (<string>a).length;let strLength2: number = (a as string).length;

Page 7: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Variable declarations

Let vs var → block-scoping (IIFE)

7

function f(shouldInitialize: boolean) { if (shouldInitialize) var x = 10; return x;}

const currentYear = 2016;currentYear--; // Re-assignment not allowed!const date = { year: 2016 };date.year--; // Okay!

Const

Destructuring 1) Array destructuring 2) Object destructuring - Property renaming - Default value 3) Function declarations

This surely deserves some more elaborated examples

function(): string { if (true) { var x = 10; var x = 5; // Okay! let y = "hola"; let y = "adiós"; // Nope! } return y; // Nope, nope!!!}

for (var i = 0; i < 10; i++) setTimeout(function() { console.log(i); }, 100 * i);

Page 8: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Interfaces (I)

Optional parameters

8

interface IPerson { firstName: string; lastName: string;}

function printName(p: IPerson) { console.log(p.firstName + " " + p.lastName);}

interface SearchFunc { (source: string, subString: string): boolean;}

let mySearch: SearchFunc;mySearch = function(src: string, subStr: string) { let result = source.search(subString); if (result === -1) { return false; } else { return true; }}

Function types

interface IPerson { firstName: string; lastName: string; middleName?: string;}

Page 9: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Interfaces (II)

Indexable types

9

interface IStringArray { [index: number]: string;}

let myArray: IStringArray;myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

interface ISquareConfig { color: string; width?: number; [propName: string]: any;}

let aa: ISquareConfig = {color: 'red', foo: 'bar'};console.log(aa.color); // redconsole.log(aa['color']); // redconsole.log(aa['foo']); // bar

Class typesinterface IClockInterface { currentTime: Date; setTime(d: Date);}

class Clock implements IClockInterface { currentTime: Date;

constructor(h: number, m: number) { // do nothing }

setTime(d: Date) { this.currentTime = d; }}

Page 10: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Interfaces (III)

Extending interfaces

10

interface IShape { color: string;}

interface ISquare extends IShape { sideLength: number;}

let square = <ISquare>{}; // type assertionsquare.color = "blue";square.sideLength = 10;

Hybrid typesinterface Counter { (start: number): string; interval: number; reset(): void;}

function getCounter(): Counter { let ctr = <Counter>function (start: number) { }; ctr.interval = 123; ctr.reset = function () { ... }; return ctr;}

let c = getCounter();c(10); // object acting as a functionc.reset(); // object acting as an objectc.interval = 5.0; // object acting as an object

Page 11: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Classes

11

class Message { mssg: string;

constructor(mssg: string) { this.mssg = mssg; }}

class Greeter extends Message { constructor(message: string) { super(message); }

greet() { return "Hello, " + this.mssg; }}

let greeter = new Greeter("world");greeter.greet();

class Message { constructor(private mssg: string); // !!!

public printOut(): void { console.log(this.mssg); // !!! }}

Parameter properties

and static properties...and static functions...and abstract classes…and property initializer (ES7)

class Message { mssg: string = undefined; ... public printOut(): void { console.log(this.mssg); }}

Page 12: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Functions (I)

12

// named functionfunction add(x: number, y: number): number { return x + y;}

// anonymous functionlet add = function(x: number, y: number): number { return x + y; };

// ...with function typelet add: (x: number, y: number) => number;add = function(x: number, y: number): number { return x + y;};

// ...letting TypeScript to infer the typeslet add: (x: number, y: number) => number;add = function(x, y) { return x + y;};

function buildName(first: string, last = "Smith") { return first + " " + name;}

Optional parameters

Default parameters

function buildName(first: string, last?: string) { if (last) return first + " " + last; else return first;}

function buildName(first: string, ...rest: string[]){ return first + " " + rest.join(" ");}

Rest parameters

Page 13: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

let deck = { suits: ["hearts", "spades", "clubs", "diamonds"], createCardPicker: function() { return function() { let card = Math.floor(Math.random() * 52); let suit = Math.floor(card / 13); return { suit: this.suits[suit], card: card % 13 }; } }}

let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();

Functions (II)

Using this (wrongly)

13

Lambda functionslet deck = { suits: ["hearts", "spades", "clubs", "diamonds"], createCardPicker: function() { return () => { let card = Math.floor(Math.random() * 52); let suit = Math.floor(card / 13); return { suit: this.suits[suit], card: card % 13 }; } }}

let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();

Captures the this available when the function is created rather than when it is invoked (ES6).

The this being used in the function created by createCardPicker will be set to window1 instead of our deck object.

1 In strict mode, this will be undefined.

Page 14: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Generics

14

function identity<T>(arg: T): T { return arg;}

let output = identity<string>("myString");

class MyNumber<T> { zeroValue: T; add: (x: T, y: T) => T;}

let myNumber = new MyNumber<number>();myNumber.zeroValue = 0;myNumber.add = function(x, y) { return x + y;};

function loggingIdentity<T>(arg: T): T { console.log(arg.length); // Error! return arg;}

interface ILengthwise { length: number;}

function loggingIdentity<T extends ILengthwise>(arg: T): T { console.log(arg.length); // Alright! return arg;}

Page 15: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Type inferences

15

window.onmousedown = function(mouseEvent) { console.log(mouseEvent.buton); // Err!};

window.onmousedown = function(mouseEvent: any) { console.log(mouseEvent.buton); // Ok!};

Best common type

Contextual Type

let x = [1, 2, null]; // inferred num[]x[2] = 'hola'; // Err!

let zoo = [new Rhino(), new Elephant(), new Snake()];// the inferred type could be Rhino[], so we couldn’t do zoo[2].creep()let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];// this is better, but still we need to do (zoo[2] as Snake).creep()

Page 16: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Advanced types (I)

Union types

16

let input: number | string | boolean;

interface Bird { fly(); layEggs();}

interface Fish { swim(); layEggs();}

function getSmallPet(): Fish | Bird { … }

let pet = getSmallPet();pet.layEggs(); // okaypet.swim(); // error! not in Fish U Bird(pet as Fish).swim() // okay for the compiler!

let pet = getSmallPet();

if ((<Fish>pet).swim) { (<Fish>pet).swim();} else { (<Bird>pet).fly();}

Type checking

function isFish(pet: Fish | Bird): pet is Fish { return (<Fish>pet).swim !== undefined;}

isFish(pet) ? pet.swim() : pet.fly();

User-defined type guards

typeof and instanceof

Page 17: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Advanced types (II)

Intersection types

17

function f<T, U>(first: T, second: U): T & U { let result = <T & U>{}; for (let id in first) (<any>result)[id] = (<any>first)[id]; for (let id in second) if (!result.hasOwnProperty(id)) (<any>result)[id] = (<any>second)[id]; return result;}

class Person { constructor(public name: string) { ... }}class Logger { log() { ... }}let jim = f(new Person("Jim"), new Logger());let name = jim.name;jim.log();

type myTpe = string | () => string;function getName(n: myType): string { return typeof n === ‘string’ ? n : n();}

Type aliases

type Easing = "ease-in" | "ease-out" | "ease-in-out";

String literal types

Page 18: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Symbols (ES6)

Declaration

18

let sym1: symbol = Symbol();

let sym2 = Symbol("key"); // optional string keylet sym = Symbol();

let obj = { [sym]: "value"};

console.log(obj[sym]); // "value"

Keys for objects

Uniquitylet sym1 = Symbol("key");let sym2 = Symbol("key");

sym1 === sym2; // false

A symbol is a unique and immutable data type and may be used as an identifier for object properties.The Symbol object is an implicit object wrapper for the symbol primitive data type...

...alright!

Page 19: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Iterators

for..of (is not for..in)

19

let list: number[] = [4, 5, 6];

for (let i of list) { console.log(i); // "4", "5", "6"}

for (let i in list) { console.log(i); // "0", "1", "2",}

let numbers = [1, 2, 3];for (let num of numbers) { console.log(num);}

In order to be iterable, an object must implement the @@iterator method, meaning that the object must have a property with a Symbol.iterator key. Array, Map, Set, String, etc. have their Symbol.iterator property already implemented.

var numbers = [1, 2, 3];for (var _i = 0; _i < numbers.length; _i++) { var num = numbers[_i]; console.log(num);}

targeting ES5 or ES3

*[Symbol.iterator]() { let i: number = 0; while(this[i] !== undefined) { yield this[i]; i++; }}

Page 20: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Generators

20

While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.

A generator is a special type of function that works as a factory for iterators. A function becomes a generator if it contains one or more yield expressions and if it uses the function* syntax.

function* idMaker(){ var index = 0; while(true) yield index++;}

var gen = idMaker();

console.log(gen.next().value); // 0console.log(gen.next().value); // 1console.log(gen.next().value); // 2

function* fibonacci(){ let fn1 = 0, fn2 = 1; while (true) { let current = fn1; fn1 = fn2; fn2 += current; yield current; }}

let sequence = fibonacci();console.log(sequence.next().value); // 0console.log(sequence.next().value); // 1console.log(sequence.next().value); // 1

Page 21: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Modules

21

class ZipCodeValidator { isAcceptable(s: string) { return s.length === 5; }}export { ZipCodeValidator };export { ZipCodeValidator as mainValidator };

Modules (external modules in TypeScript 1.5) are executed within their own scope, not in the global scope; variables, functions, classes, etc. declared in a module are not visible outside the module unless they are explicitly exported. Conversely, to consume a variable, function, class, interface, etc. exported from a different module, it has to be imported.

In TypeScript (and in ES6) any file containing a top-level import or export is considered a module.

Page 22: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Namespaces

22

namespace Validation { export interface StringValidator { isAcceptable(s: string): boolean; }}

let f: Validation.StringValidator = isAcceptable(s: string): boolean { ... }

Namespaces (internal modules in TypeScript 1.5) are a way to wrap objects avoiding to put lots of different names into the global namespace.To declare anything that shall be visible from outside the namespace, we need to use export.

Page 23: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Triple-Slash directives

23

Triple-slash directives are single-line comments containing a single XML tag. The contents of the comment are used as compiler directives.

❖ Triple-slash directives are only valid at the top of their containing file.❖ A triple-slash directive can only be preceded by single or multi-line comments, including other

triple-slash directives.❖ If they are encountered following a statement or a declaration they are treated as regular single-

line comments, and hold no special meaning.

/// <reference path=”...” /> serves as a declaration of dependency between files.Triple-slash references instruct the compiler to include additional files in the compilation process.They also serve as a method to order the output when using --out or --outFile.

/// <reference path="..." />

Page 24: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Map files

24

• Source map files let tools map between the emitted JavaScript code and the TypeScript source files that created it.

• Many debuggers (VisualStudio Code or Chrome's dev tools) can consume these files so you can debug the TypeScript file instead of the JavaScript file.

• This is the same source map format being produced by some minifiers and other compiled-to-JS languages like CoffeeScript.

Page 25: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

TypeScript definitions & TSD (I)

25

• When using TypeScript, you will need TypeScript definition files to work with external libraries.

• A lot of those definition files (.d.ts) are available on GitHub: DefinitelyTyped. At the time of writing, there are 1921 entries. At the time of reviewing (one week later), 1933.

• To use these files in your project, you can simply download and copy them to your project.

• We can also use TSD, the TypeScript Definitions Manager. TSD is a package manager to search and install definition files directly from the DefinitelyTyped repository.

Page 26: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

TypeScript definitions & TSD (II)

26

# Installation$ npm install tsd -g

# Create a new tsd.json and tsd.d.ts$ tsd init

# Get some info about a package$ tsd query jquery --info --resolve

# Install a package into our project$ tsd install angular-mock

# Install a package into our project and save it into tsd.json$ tsd install angular-mock --save

# Install all the references from tsd.json$ tsd install

Page 27: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Typings (I)

27

• Typings is a simpler way to manage and install TypeScript definitions.

• It uses typings.json, which can resolve to the Typings Registry, GitHub, NPM, Bower, HTTP and local files.

• Packages can use type definitions from various sources and different versions.

Page 28: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Typings (II)

28

# Install Typings CLI utility$ npm install typings --global

# Find an available definition by name$ typings search --name react

# Creates or update the typings.json file from a previous tsd.json file$ typings init --upgrade

# Install all the typings described in typings.json$ typings install

Page 29: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

29

Questions?

Page 30: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

Sources• TypeScript 1.8 Language Specification at Microsoft’s GitHub (Jan, 2016):

https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md

• TypeScript Deep Dive (Basarat Ali Syed - Last edition: today!):https://www.gitbook.com/book/basarat/typescript/details

• Mozilla’s JavaScript Reference:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference

All the source code available at Epic Labs’ GitHub soon:https://github.com/epiclabs-io

30

Page 31: TypeScript - All you ever wanted to know - Tech Talk by Epic Labs

#BeEpic!

epiclabs.io