Typescript tips & tricks

35
TYPESCRIPT TIPS & TRICKS Ori Calvo, 2017 [email protected] https://trainologic.com

Transcript of Typescript tips & tricks

TYPESCRIPT TIPS

& TRICKS

Ori Calvo, 2017

[email protected]

https://trainologic.com

2

Objectives© 2017 Ori Calvo

2

Cover all the “good to know” details about

Typescript

This is not an introduction session

3

The Challenge© 2017 Ori Calvo

3

Write today modern JavaScript code

Even before browsers support that

Solution: Compiler ESX ES5

Alternatives

Typescript

Babel

CoffeeScript

Traceur

4

Getting Started© 2017 Ori Calvo

4

npm install typescript

Write some Typescript code

Compile it with node_modules/.bin/tsc

Run the generated JavaScript

Use source map to debug the TypeScript

5

Good to Know© 2017 Ori Calvo

5

Partial typeDecoratorsBarrelHow does import/export work

Down-level support for async/await

Down-level

generator support

User defined type guard

union/intersection type

String EnumsCreate NPM package

--initstrictNullChecksstrict master option

Generic parameter defaultModule augmentations

--declarationTyped map using object

object typeMixincheckJs & allowJs

noImplicitAnyUntyped importstslibObject spread & restkeyof

Return value from ctor

Configuration Inheritance

--alwaysStrictType guardsNon null assertion

nevertype of thisGlob Supportpaths--traceResolution

Wildcard module name

script vs. module--lib--noUnusedXXXWhy use target es5 with module es6

Trailing commas

6

script vs. module© 2017 Ori Calvo

6

Only files which use the import/export syntax

are considered modules

Other are considered “plain” scripts

Module does not pollute the global scope

Script does

7

script vs. module© 2017 Ori Calvo

7

Below code does not work

Remove the export keyword and code compiles successfully

export function xxx() {}

interface Contact {id: number;name: string;

}

var x: Contact = {id: 1,name: "Ori",

};

8

import/export© 2017 Ori Calvo

8

export function run() {console.log("run");

}

import {run} from "./module1";

run();

import * as module1 from "./module1";

module1.run();

9

import/export© 2017 Ori Calvo

9

Part of ECMAScript 2015

No easy way to support under ES5

Must select a module “standard”

amd

commonjs

umd

es2015

10

import/export© 2017 Ori Calvo

10

Most browsers do not supports import/export

Coming Chrome 62 will

Therefore, must use a module loader

Webpack

Rollup

Fusebox

SystemJS

11

Barrel© 2017 Ori Calvo

11

Rollup exports from several modules into a single convenient module

12

async/await© 2017 Ori Calvo

12

function delay(ms) {

return new Promise(function(resolve) {

setTimeout(function() {

resolve();

}, ms);

});

}

async function run() {

await delay(500);

console.log("AFTER");

}

13

async/await© 2017 Ori Calvo

13

Part of ECMAScript 2017

Allow for easier implementation of

asynchronous functions

Is supported for down-level browsers too

Debugging is challanging

14

Decorator© 2017 Ori Calvo

14

Attach metadata to methods/classes

Like C# attribute

Java annotation

Can intercept function invocation

15

Decorator© 2017 Ori Calvo

15

class Contact {@Profile()run() {

console.log("run");}

} function Profile() {return function(target,propertyKey: string, descriptor: PropertyDescriptor) {

const original = target[propertyKey];

target[propertyKey] = function() {console.log("BEFORE");const retVal = original.apply(this, arguments);console.log("AFTER");

return retVal;}

return target;}

}

16

Create NPM package© 2017 Ori Calvo

16

Enable declaration option

Use es2015 module settings

Bundle all files into UMD format

Rollup can help

Add package.json

main option inside package.json should point

to the UMD bundle

npm publish

17

String Enums© 2017 Ori Calvo

17

Enums can now be of type string

enum Color {red = "Red",green = "Green",blue = "Blue",

}

const c: Color = Color.red;

var Color;(function (Color) {

Color["red"] = "Red";Color["green"] = "Green";Color["blue"] = "Blue";

})(Color || (Color = {}));

18

Union Type© 2017 Ori Calvo

18

Create a new type which one of the specified

interface A {id: number,

}

interface B {name: string,

}

type C = A | B;

const c1: C = {id: 1,

};

const c2: C = {name: "Ori",

};

19

Intersection Type© 2017 Ori Calvo

19

Define new type which has properties of all the others

interface A {id: number,

}

interface B {name: string,

}

type C = A & B;

const c1: C = {id: 1,name: "Ori",

};

20

Object.assign© 2017 Ori Calvo

20

Using previous syntax we can now define Object.assign in a type safe way

interface ObjectConstructor {assign<T, U>(target: T, source: U): T & U;

assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;

assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;}

21

Type Guard© 2017 Ori Calvo

21

The following compiles successfully

class A {}

class B extends A {run() {}

}

function doSomething(a: A) {if(a instanceof B) {

a.run();}

}

22

Challenge© 2017 Ori Calvo

22

However, the following does not compile successfullyclass A {

}

class B extends A {run() {}

}

function isB(a: A) {return a instanceof B;

}

function doSomething(a: A) {if(isB(a)) {

a.run();}

}

Property

'run' does

not exist on type 'A'.

23

User Type Guard© 2017 Ori Calvo

23

We can fix that

class A {}

class B extends A {run() {}

}

function isB(a: A): a is B {return a instanceof B;

}

function doSomething(a: A) {if(isB(a)) {

a.run();}

}

24

Class Augmentation© 2017 Ori Calvo

24

An interface can extend existing class

class A {run() {}

}

interface A {doSomething();

}

function main() {const a = new A();

a.doSomething();}

main();

25

Module Augmentation© 2017 Ori Calvo

25

Extend a class exported from a module

export class A {run() {}

}

module1

import {A} from "./module1";

declare module "./module1" {interface A {

doSomething();}

}

function main() {const a = new A();

a.doSomething();}

Application code

26

Null Checks© 2017 Ori Calvo

26

The following does compile successfully

class A {run() {}

}

function run(a: A) {a.run();

}

function main() {run(null);

}

27

--strictNullChecks© 2017 Ori Calvo

27

If on (default is off), the compiler assume that

any type is not assignable with null or

undefined

Now, the following code does not compile

{"compilerOptions": {

"strictNullChecks": true}

}

function main() {run(null);

}

28

Allow null© 2017 Ori Calvo

28

class A {run() {}

}

function run(a: A|null) {if(a) {

a.run();}

}

function main() {run(null);

}

Without the if

the error

“object is

possibly null” is reported

29

--allowJs

© 2017 Ori Calvo

29

Tells the Typescript compiler to allow import of

a JS file

The JS file will be verified

But only for general syntax errors

Type safe errors are not reported

import/export will be converted to the specified

module system

30

--checkJs

© 2017 Ori Calvo

30

Tells Typescript compiler to verify Type checks

as much as it can

Sending parameters to a function

Types are calculated based on initialization

Can use JSDoc to annotate code with types

For example,

function g(/** @type{string} */ a) {

a = 12;

}

31

Mixin

© 2017 Ori Calvo

31

Create a new class out of an existing one and

add some “features” to it

class A {constructor(name: string) {}

}

type Constructor<T> = new(...args: any[]) => T;

function createClass<T extends Constructor<{}>>(Base: T, id) {return class extends Base {

id: number = id;}

}

var B = createClass(A, 5);var b = new B("Ori");console.log(b.id);

32

Typed map using object

© 2017 Ori Calvo

32

class Point {constructor(private x: number, private y: number) {}

}

const map: {[key: string]: Point} = {};

map["abc"] = new Point(5, 10);

33

keyof

© 2017 Ori Calvo

33

interface Person {id: number;

}

type K1 = keyof Person; // id

function get<T, K extends keyof T>(obj: T, name: K): T[K] {return obj[name];

}

var x: Person = {id:5};get(x, "id");

34

Partial

© 2017 Ori Calvo

34

interface Person {id: number;name: string;

}

type PartialPerson = Partial<Person>;

const x: PartialPerson = {id: 1,

};

THANK YOU

Ori Calvo, 2017

[email protected]

https://trainologic.com