Upload
alfonso-peletier
View
102
Download
0
Embed Size (px)
Citation preview
TypeScript 1.8
All you ever wanted to know by Adrián Caballero
July 2016
TypeScriptTM is a typed object-oriented superset of JavaScript that transcompiles to plain JavaScript.
3
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
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};
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;
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);
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;}
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; }}
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
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); }}
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
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.
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;}
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()
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
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
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!
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++; }}
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
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.
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.
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="..." />
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.
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.
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
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.
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
29
Questions?
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
#BeEpic!
epiclabs.io