Einführung in TypeScript

58
TypeScript Lukas Gamper Demian Holderegger uSystems GmbH

Transcript of Einführung in TypeScript

TypeScriptLukas GamperDemian HoldereggeruSystems GmbH

Agenda

TypeScript: Die Sprache

TypeScript in der Praxis

Wie ist TypeScript entstanden?

- 2011 Entwicklung von ES6 beginnt - 2012 Microsoft entwickelt TypeScript- 2015 Angular2 mit TypeScript

Einsatz von TypeScript

TypeScript:die Sprache

Was ist TypeScript?

- Kompiliert nach JavaScript

- Generiert lesbaren JS Code

Was ist TypeScript?

- Superset von ES6

- Unterstützt Typen

ES6 Support

Vorteile von Typescipt

- Keine Typenfehler mit Strong Typing- ES6 kann schon jetzt benutzt werden:

- Besser strukturiert mit Klassen- Viele Sprachverbesserungen wie

let, for … of, ()=>..., etc.

- Boolean, Number, String- Array, Tuple- Enum- Function- Object- Void- Any

Statische Typen

var isDone: boolean = false;

Boolean

var height: number = 6;

Number

var name: string = "bob";name = 'smith';

String

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

Array

var tuple:[number, string] = [1, "bob"];

var secondElement:string = tuple[1];

Tuple

enum Color {Red, Green, Blue=4};var c: Color = Color.Green;

Enum

var cb:(name:string):string = function(name:string):string { return ‘Hello ’ + Bob; }

console.log(cb(‘Bob’)) // Hello Bob

Function

var square:{color:string; area:number} = {color: white, area: 100}

Object

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

Void

var notSure: any = 4;var unknown = ‘foo’;

Any

Klassen

TypeScript

class Greeter {

greeting: string;

constructor(message: string) {

this.greeting = message;

}

greet():string {

return "Hello, " + this.greeting;

}

}

var greeter = new Greeter("world");

JavaScript

function Greeter(message) {

this.greeting = message;

}

Greeter.prototype.greet = function() {

return "Hello, " + this.greeting;

}

var greeter = new Greeter("world");

Private / Public

class Greeter {

private greeting: string;

constructor(message: string) {

this.greeting = message;

}

greet() {

return "Hello, " + this.greeting;

}

}

var greeter = new Greeter("world");

class Greeter {

constructor(private greeting: string) {}

greet() {

return "Hello, " + this.greeting;

}

}

var greeter = new Greeter("world");

class Animal {

constructor(public name: string) {}

move(meters: number = 0):void {

alert(this.name + ": " + meters);

}

}

class Snake extends Animal {

constructor(name: string) {

super(name);

}

move(meters: number = 5):void {

alert("Slithering...");

super.move(meters);

}

}

Vererbung

class Horse extends Animal {

constructor(name: string) {

super(name);

}

move(meters: number = 45):void {

alert("Galloping...");

super.move(meters);

}

}

Interfaces

interface AnimalInterface {

name:string;

constructor(theName: string);

move(meters: number) ;

}

interface ReptileInterface {}

interface SnakeInterface

extends AnimalInterface, R eptileIn

{

constructor(name: string)

move(meters: number);

}

class Animal implements AnimalInterface {

constructor(public name: string) {}

move(meters: number = 0) {

alert(this.name + " moved " + meters + "m.");

}

}

class Snake extends Animal implements SnakeInterface, R eptileInterface {

constructor(name: string) { super(name); }

move(meters: number = 5) {

alert("Slithering...");

super.move(meters);

}

}

Arrow Functions ()=>...

- kein function keyword- kein Scope

- this von outer scope vererbt- arguments bleibt unverändert- bind hat keine Wikrung

Arrow Functions ()=>...

mit brackets

var inc = (arg:number):number => {

return a + 1

}

ohne brackets

var inc = (a)=>a+1

JavaScript

var inc = function(arg:number):number {

return a + 1

}

Arrow Functions ()=>...

JavaScript

function Person(age) {

this.age = age

this.growOld = (function(){

++this.age;

}).bind(this);

}

let person = new Person(1);

person.growOld()

TypeScript

function Person(age) {

this.age = age

this.growOld = ():void=>{

++this.age;

}

}

let person = new Person(1);

person.growOld()

let

▪ Variablen in ES5 sind function scoped▪ Let definiert block scoped Variablen▪ Zugriff auf let Variablen vor ihrer

definition wirft ReferenceError

let

JavaScript

var foo = 123;

if (true) {

var foo = 456;

}

console.log(foo); // 456

TypeScript

let foo = 123;

if (true) {

let foo = 456;

}

console.log(foo); // 123

let

JavaScript

var vals = [];

for (var x = 0; x < 4; ++x)

vals.push(()=>x);

console.log(vals.map(cb=>cb()));

// [4, 4, 4, 4]

typeScript

let vals = [];

for (let x = 0; x < 4; ++x)

vals.push(()=>x);

console.log(vals.map(cb=>cb()));

// [0, 1, 2, 3]

String Templates - Multiline String

JavaScript

var lyrics = "Never gonna give you up \\nNever gonna let you down";

TypeScript

var lyrics = `Never gonna give you upNever gonna let you down`;

String Templates - String Interpolation

JavaScript

var lyrics = 'Never gonna give you up';var a = '<div>' + lyrics + '</div>';

var b = ‘1 and 1 one make ' + (1 + 1)

TypeScript

var lyrics = 'Never gonna give you up';var a = `<div>${lyrics}</div>`;

var b = `1 and 1 one make ${1 + 1}`

for … of

var someArray = [9, 2, 5];

for (var item in someArray) {

console.log(item); // 0,1,2

}

var someArray = [9, 2, 5];

for (var item of someArray) {

console.log(item); // 9,2,5

}

Beispiel: Grid von vuejs.org

/// <reference path="vue-component.ts" />

@createComponent('demo-grid')class DemoGrid extends ComponentBase {

static template:string = '#grid-template';

@prop({ type: Array, required: true }) data:Array<{name: string, power:number }>;

@prop({ type: Array, required: true }) columns:Array< string>;

sortKey:string = '';

reversed:{[key: string]: boolean} = {};

@hook('compiled') compiled():void { this.columns.forEach((key: string):void => { this.$set(`reversed.${key}`, false); }); }

sortBy(key:string):void { this.sortKey = key; this.reversed[key] = ! this.reversed[key]; }}

Vue.component('demo-grid', { template: '#grid-template', props: { data: {type:Array, required: true}, columns: {type:Array, required: true} }, data: function () { return { data: null, columns: null, sortKey: '', rev: {} }; }, compiled: function () { var self = this; this.columns.forEach( function (key) { self.$set(rev.' + key, false); }); }, methods: { sortBy: function (key) { this.sortKey = key; this.rev[key] = !this.rev[key]; } }});

/// <reference path="vue-component.ts" />

@createComponent('demo-grid')class DemoGrid extends ComponentBase {

static template:string = '#grid-template';

@prop({ type: Array, required: true }) data:Array<{name: string, power:number }>;

@prop({ type: Array, required: true }) columns:Array< string>;

sortKey:string = '';

reversed:{[key: string]: boolean} = {};

@hook('compiled') compiled():void { this.columns.forEach((key: string):void => { this.$set(`reversed.${key}`, false); }); }

sortBy(key:string):void { this.sortKey = key; this.reversed[key] = ! this.reversed[key]; }}

Vue.component('demo-grid', { template: '#grid-template', props: { data: {type:Array, required: true}, columns: {type:Array, required: true} }, data: function () { return { data: null, columns: null, sortKey: '', rev: {} }; }, compiled: function () { var self = this; this.columns.forEach( function (key) { self.$set(rev.' + key, false); }); }, methods: { sortBy: function (key) { this.sortKey = key; this.rev[key] = !this.rev[key]; } }});

Decorators / Annotations

/// <reference path="vue-component.ts" />

@createComponent('demo-grid')class DemoGrid extends ComponentBase {

static template:string = '#grid-template';

@prop({ type: Array, required: true }) data:Array<{name: string, power:number }>;

@prop({ type: Array, required: true }) columns:Array< string>;

sortKey:string = '';

reversed:{[key: string]: boolean} = {};

@hook('compiled') compiled():void { this.columns.forEach((key: string):void => { this.$set(`reversed.${key}`, false); }); }

sortBy(key:string):void { this.sortKey = key; this.reversed[key] = ! this.reversed[key]; }}

Vue.component('demo-grid', { template: '#grid-template', props: { data: {type:Array, required: true}, columns: {type:Array, required: true} }, data: function () { return { data: null, columns: null, sortKey: '', rev: {} }; }, compiled: function () { var self = this; this.columns.forEach( function (key) { self.$set(rev.' + key, false); }); }, methods: { sortBy: function (key) { this.sortKey = key; this.rev[key] = !this.rev[key]; } }});

Klassen und Typen

/// <reference path="vue-component.ts" />

@createComponent('demo-grid')class DemoGrid extends ComponentBase {

static template:string = '#grid-template';

@prop({ type: Array, required: true }) data:Array<{name: string, power:number }>;

@prop({ type: Array, required: true }) columns:Array< string>;

sortKey:string = '';

reversed:{[key: string]: boolean} = {};

@hook('compiled') compiled():void { this.columns.forEach((key: string):void => { this.$set(`reversed.${key}`, false); }); }

sortBy(key:string):void { this.sortKey = key; this.reversed[key] = ! this.reversed[key]; }}

Vue.component('demo-grid', { template: '#grid-template', props: { data: {type:Array, required: true}, columns: {type:Array, required: true} }, data: function () { return { data: null, columns: null, sortKey: '', rev: {} }; }, compiled: function () { var self = this; this.columns.forEach( function (key) { self.$set(rev.' + key, false); }); }, methods: { sortBy: function (key) { this.sortKey = key; this.rev[key] = !this.rev[key]; } }});

Arrow Functions

/// <reference path="vue-component.ts" />

@createComponent('demo-grid')class DemoGrid extends ComponentBase {

static template:string = '#grid-template';

@prop({ type: Array, required: true }) data:Array<{name: string, power:number }>;

@prop({ type: Array, required: true }) columns:Array< string>;

sortKey:string = '';

reversed:{[key: string]: boolean} = {};

@hook('compiled') compiled():void { this.columns.forEach((key: string):void => { this.$set(`reversed.${key}`, false); }); }

sortBy(key:string):void { this.sortKey = key; this.reversed[key] = ! this.reversed[key]; }}

Vue.component('demo-grid', { template: '#grid-template', props: { data: {type:Array, required: true}, columns: {type:Array, required: true} }, data: function () { return { data: null, columns: null, sortKey: '', rev: {} }; }, compiled: function () { var self = this; this.columns.forEach( function (key) { self.$set(rev.' + key, false); }); }, methods: { sortBy: function (key) { this.sortKey = key; this.rev[key] = !this.rev[key]; } }});

String Template

Vorteile

TypeScript in der Praxis

Native Unterstützung in PHPStorm 9

Native Unterstützung in PhpStorm 9

Debugging

Debugging im Chrome

Breakpoints

source map files

Einbinden in bestehenden Code

JavaScript ist TypeScript!

DefinitelyTyped

Interface Dateien für bestehende Libraries

http://definitelytyped.org/

DefinitelyTyped

▪ GitHub Repo mit über 1000 *.d.ts Dateien von bekannten Libraries

▪ Einfach selber zu schreiben: es sind nur Interfaces

DefinitelyTypedBeispiel: jQuery

$(“.myclass”); // Liste der Elemente

declare var $: JQuery;

interface JQuery {

(selector: string): JQueryObject;

...

}

DefinitelyTypedBeispiel: AngularJS $http Service

interface IHttpService {

post<T>(

url: string,

data: any,

config?: IRequestShortcutConfig

): IHttpPromise<T>;

...

}

DefinitelyTyped

Yet Another Package Manager: tsd

▪ ähnlich wie Bower▪ erstellt Reference Datei mit allen

includes▪ Manifest Datei: tsd.json

Testing

▪ Grundsätzlich gleich wie mit JavaScript

▪ Tests in TypeScript schreiben (.d.ts)▪ tsUnit

Ausblick

- generators (1.6)

- await / async (2.0)

Pro

▪ weniger Fehler▪ schönerer Code▪ schnellere Entwicklung▪ Modularisierung

Cons

▪ .d.ts Dateien teilweise veraltet▪ Dokumentation nicht up to date▪ Muss immer kompiliert werden

Thank you!

www.usystems.ch

function *g(limit) {

for (var i = 0; i < limit; i++) {

yield i;

}

}

for (let i of g(100)) {

console.log(i);

}

var array = [...g(50)];

var [first, second, ...rest] = g(100);

Backup: generators

async myFunction(): Promise<any> {

var result = await loadAjaxData();

return result;

}

Backup: await / async

function foo(x) {

while (true) {

x = x * 2;

yield x;

}

}

var g = foo(2);

g.next(); // -> 4

g.next(); // -> 8

g.next(); // -> 16

Backup: yield