TYPESCRIPT TIPS
& TRICKS
Ori Calvo, 2017
oric@trainologic.com
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/intersecti
on 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();
}
Applicatio
n 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
oric@trainologic.com
https://trainologic.com

Typescript tips & tricks

  • 1.
    TYPESCRIPT TIPS & TRICKS OriCalvo, 2017 [email protected] https://trainologic.com
  • 2.
    2 Objectives © 2017 OriCalvo 2  Cover all the “good to know” details about Typescript  This is not an introduction session 
  • 3.
    3 The Challenge © 2017Ori Calvo 3  Write today modern JavaScript code  Even before browsers support that  Solution: Compiler ESX  ES5  Alternatives  Typescript  Babel  CoffeeScript  Traceur
  • 4.
    4 Getting Started © 2017Ori 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.
    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/intersecti on 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.
    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.
    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.
    8 import/export © 2017 OriCalvo 8 export function run() { console.log("run"); } import {run} from "./module1"; run(); import * as module1 from "./module1"; module1.run();
  • 9.
    9 import/export © 2017 OriCalvo 9  Part of ECMAScript 2015  No easy way to support under ES5  Must select a module “standard”  amd  commonjs  umd  es2015
  • 10.
    10 import/export © 2017 OriCalvo 10  Most browsers do not supports import/export  Coming Chrome 62 will  Therefore, must use a module loader  Webpack  Rollup  Fusebox  SystemJS
  • 11.
    11 Barrel © 2017 OriCalvo 11  Rollup exports from several modules into a single convenient module
  • 12.
    12 async/await © 2017 OriCalvo 12 function delay(ms) { return new Promise(function(resolve) { setTimeout(function() { resolve(); }, ms); }); } async function run() { await delay(500); console.log("AFTER"); }
  • 13.
    13 async/await © 2017 OriCalvo 13  Part of ECMAScript 2017  Allow for easier implementation of asynchronous functions  Is supported for down-level browsers too  Debugging is challanging
  • 14.
    14 Decorator © 2017 OriCalvo 14  Attach metadata to methods/classes  Like C# attribute  Java annotation  Can intercept function invocation
  • 15.
    15 Decorator © 2017 OriCalvo 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.
    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.
    17 String Enums © 2017Ori 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.
    18 Union Type © 2017Ori 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.
    19 Intersection Type © 2017Ori 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.
    20 Object.assign © 2017 OriCalvo 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.
    21 Type Guard © 2017Ori Calvo 21  The following compiles successfully class A { } class B extends A { run() { } } function doSomething(a: A) { if(a instanceof B) { a.run(); } }
  • 22.
    22 Challenge © 2017 OriCalvo 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.
    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.
    24 Class Augmentation © 2017Ori Calvo 24  An interface can extend existing class class A { run() { } } interface A { doSomething(); } function main() { const a = new A(); a.doSomething(); } main();
  • 25.
    25 Module Augmentation © 2017Ori 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(); } Applicatio n code
  • 26.
    26 Null Checks © 2017Ori Calvo 26  The following does compile successfully class A { run() { } } function run(a: A) { a.run(); } function main() { run(null); }
  • 27.
    27 --strictNullChecks © 2017 OriCalvo 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.
    28 Allow null © 2017Ori 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.
    29 --allowJs © 2017 OriCalvo 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.
    30 --checkJs © 2017 OriCalvo 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.
    31 Mixin © 2017 OriCalvo 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.
    32 Typed map usingobject © 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.
    33 keyof © 2017 OriCalvo 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.
    34 Partial © 2017 OriCalvo 34 interface Person { id: number; name: string; } type PartialPerson = Partial<Person>; const x: PartialPerson = { id: 1, };
  • 35.
    THANK YOU Ori Calvo,2017 [email protected] https://trainologic.com