Post on 11-Jul-2020
TypeScript für Fortgeschrittene
Tobias Meier, BridgingIT GmbHhttp://blog.bridging-it.de/author/Tobias.Meier
Tobias MeierLead Softwarearchitekt Microsoft
Wir bringen Dinge zusammen
Blog: http://blog.bridging-it.de/author/Tobias.Meier
Twitter: @bitTobiasMeier
Email: Tobias.Meier@bridging-it.de
„
Standort Nürnberg
Königtorgraben 11
90402 Nürnberg
Standort Zug/Schweiz
Baarerstraße 14
CH-6300 Zug
Standort Mannheim
N7, 5-6
68161 Mannheim
Standort Karlsruhe
Rüppurrer Straße 4
76137 Karlsruhe
Standort Stuttgart
Marienstraße 17
70178 Stuttgart
Standort München
Riesstraße 12
80992 München
Standort Frankfurt
Solmsstraße 4
60486 Frankfurt
Standort Köln
Martinstraße 3
50667 Köln
Copyright © BridgingIT GmbH | Autor: Tobias Meier | Mai 2017 | www.bridging-it.de
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
JavaScript
Intellisense
Typsicherheit
Compiler
Refactoring
…….
Warum TypeScript ?
Great tooling enabled by static types
Features from the future today
Wie verwendet ihr TypeScript ?
VSCode
AutoImport
Debugger for Chrome, Edge
TSLint
Codelens, Code Metrics
Angular Language Service
Tooling in VSCode
Quick Fixes
Autoimport
Codelens
Code Metrics
Angular Language Service
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
Aufwärmübung
var conference = 'DevDays Magdeburg';
for (var i=2016; i< 2017; i++) {
var conference = 'Dev Days Magdeburg ' +i;
console.log (conference);
}
console.log (conference);
Aufwärmübung 1
var conference = 'DevDays Magdeburg';
for (var i = 2016; i < 2017; i++) {
var conference = 'Dev Days Magdeburg ' + i;
console.log(conference);}console.log(conference);
Aufwärmübung 2
let conference = 'DevDays Magdeburg';
for (var i = 2016; i < 2017; i++) {
let conference = 'Dev Days Magdeburg ' + i;
console.log(conference);}console.log(conference);
Aufwärmübung 3
const conference = 'DevDays Magdeburg';
for (var i = 2016; i < 2017; i++) {
conference = 'Dev Days Magdeburg ' + i;
console.log(conference);
}
console.log(conference);
Destructuring (1/4)
const sessions = ['IOT', 'TypeScript', 'Automatisieren']
const [session1, session2, session3] = sessions;
console.log(session1);
console.log(session2);
console.log(session3);
Destructuring (2/4)
const sessions = ['IOT', 'TypeScript', 'Automatisieren']
const [session1, ...weitereSessions] = sessions;
console.log(session1);
console.log(weitereSessions.join());
Destructuring (3/4)
const person = {
firstname: 'Tobias', surname: 'Tobias', plz: '70178', city: 'Stuttgart',
street: 'Marienstraße 17'
};
const { firstname, surname, ...address } = person;
console.log(firstname);console.log(surname);console.log(address.plz);console.log(address.city);console.log(address.street);
Destructuring (4/4)
const person = {firstname: 'Tobias', surname: 'Tobias',plz: '70178', city:'Stuttgart', street:'Marienstraße 17'
};
const {firstname :vorname, surname:nachname,
...address: adresse} = person;
console.log (vorname);console.log (nachname);console.log(adresse.plz);console.log(adresse.city);console.log(adresse.street);
Parameter: Optional, Default, Sonstige
function buildAddress(firstname: string,
surname?: string, ...address: string[]) {
let result = surname;
if (surname) result = result + ' ' + surname;
return result + address.join(' ');
}
console.log(buildAddress('Tobias', 'Meier','70178','Stuttgart', 'Marienstr. 17'));
Klasse als Interface verwenden
class Person{
name: string;
}
interface OnlinePerson extends Person {
email: string;
}
const person: OnlinePerson = {name: 'Meier', email: 'tobias.meier@bridging-it.de'};
console.log (person.email);
Spread
let original = { name: 'Tobias' };let address = { city: 'Stuttgart' };let copy = { ...original };let merged = { ...original, ...address };
let obj = { x: 1, y: "string" };var newObj = { ...obj, z: 3, y: 4 };
Rest
let obj = { x: 1, y: 1, z: 1
};
let { z, ...obj1 } = obj;
console.log (obj1.x);
console.log (obj1.y);
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
Null und undefined
function add (zahl1: number, zahl2: number | null):number{
return zahl1 + (zahl2 != null ? zahl2 : 0);}
var result = add (1,1); // => 2var result = add (1,null); // => 1
//Kompilierfehlervar result = add (null,1);
tsconfig.json
"compilerOptions": {"strictNullChecks": true
}
Nun auch in Angular verwendbar: Angular 4.1.2
Intersection Types
interface Company { name: string}
interface Address { street: string, plz: string, city:string }
type CompanyWithAddress = Company & Address
const person : CompanyWithAddress = {
name: "BridgingIT GmbH",
plz: "70178",
city: "Stuttgart",
street: "Marienstraße 17"
} ;
Datentypen: Union Types
function sum (x: number | number[]) { if (typeof x === "number") {
return x + 10; } else {
// return sum of numbers}
}
Type Guard typeof
function format(obj: string | number): string {
if (typeof obj === 'number') {
return obj.toLocaleString();
}
return obj;
}
console.log( format("abc") );
console.log( format(10.124));
Type Guard instanceof
class Person {constructor(public firstname: string, public lastname: string){}
}class Company { constructor(public companyname: string) { } }
function getName(obj: Person | Company): string {
if (obj instanceof Person) {
return obj.firstname + ' ' + obj.lastname;
}
return obj.companyname;
}
Eigene Type Guards
function isPerson(obj: Person | Company): obj is Person {if (obj instanceof Person) {return true;
}return false;
}
var obj: Person | Company = new Company("BridingIT GmbH");if (isPerson(obj)) { console.info(obj.lastname); }else { console.info(obj.companyname); }
Discriminated Union
interface Square {kind: "square";size: number;
}
interface Rectangle {kind: "rectangle";width: number;height: number;
}
interface Circle {kind: "circle";radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle":
return s.width * s.height;
case "circle":
return Math.PI *s.radius * s.radius;
}
}
Fluent API: Polymorphic this
class StringBuilder {
add (str: string) : this {
//…return this;
}}
class AdvancedStringBuilder extends StringBuilder {
appendLine () : this { return this;
}}
new AdvancedStringBuilder().add('Hello').appendLine();
Mapped Types
class User {
firstname: string;
surname: string;
}
interface ReadonlyUser {
readonly firstname: string;
readonly surname: string;
}
const user = new User();
user.firstname = 'Tobias';
user.surname = 'Meier';
const ruser = <ReadonlyUser> user;
ruser.firstname = "tobias";
Mapped Types: Readonly
class User {
firstname: string;
surname: string;
}
const user = new User();
user.firstname = 'Tobias'; user.surname = 'Meier';
const ruser = <Readonly<User>> user;
ruser.firstname = "tobias";
Mapped Types: Partial
class User {
firstname: string;
surname: string;
}
const user : User = {firstname: 'Tobias'; }
const puser : <Partial<User>> = {firstname: 'Tobias'; }
Und wie lautet der Zaubertrick ?
Keyof-Operator
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
type Partial<T> = {
[P in keyof T]?: T[P];
}
Mapped Types: Record
type Person =
Record<'firstname' | 'surname' | 'email', string>;
const person1 = <Person> {
firstname:"Tobias",
surname:"Meier",
email:"tobias.meier@bridging-it.de"
};
Mapped Types: Pick
type Person=Record<'firstname'|'surname'|'email',string>;
const P1 = <Person> {
firstname:"Tobias", surname:"Meier",
email:"tobias.meier@bridging-it.de"
};
type OnlinePerson = Pick<Person, 'email'>;
const P2 = <OnlinePerson> P1;
console.log(P2.email);
Keyof-Operator Record und Pick
type Record<K extends string | number, T> = {[P in K]: T;
}
type Pick<T, K extends keyof T> = {[P in K]: T[P];
}
String Literal Types
type Direction= "north" | "south" | "west" | "east";function drive (dir: Direction) {//….}
drive ('north'); //okdrive ('east'); //ok
drive ('n'); //error
Type Assertions
interface SquareConfig { color?: string; width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } { return null;
}
let mySquare = createSquare({ colour: "red", width: 100 } );
Type Assertions
interface SquareConfig { color?: string; width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } { return null;
}
let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig
);
Type Assertions
interface SquareConfig {
color?: string; width?: number;
[propName: string]: any;
}
function createSquare(config: SquareConfig): {
color: string; area: number } {
//..}
let mySquare = createSquare( { colour: "red", width: 100 });
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
async / await
async function main() {
await ping();
}
async function ping() {
for (var i = 0; i < 10; i++) {
await delay(300); console.log("ping");
}
}
function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
main();
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
Decorator
Entspricht Attributen in C#
Feature muss explizit aktiviert werden:
In Angular stark verwendet:
Eigener Decorator (1/2)
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
Eigener Decorator (2/2):function logger(): any {return function (target: any, propertyKey: string, descriptor:
PropertyDescriptor) {const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) {
console.log("Called method " + propertyKey +" (" + JSON.stringify(args) +")");const result = originalMethod.apply(this, args);console.log("Method " + propertyKey +" returns:" + result);return result;
};return descriptor;
}};
var sb = new StringBuilder();sb.add('Hallo').add(' Magdeburg');
Mixins
class Person{
///...
}
export type Constructable = new (...args: any[]) => object;
export function Timestamped<BC extends Constructable>(Base: BC) {
return class extends Base {
timestamp = new Date();
};
}
const TimestampedPerson= Timestamped(Person);
const person1 = new TimestampedPerson();
console.info (person1.timestamp);
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
Modulauflösung
Angelehnt an NodeJS
Tracing :
tsconfig.json
{"compilerOptions": {
"moduleResolution": "node","traceResolution": true}
}
Modulauflösung (relativ)
File Main.ts:
File 'C:/Projekte/ET/ts/customer.ts' does not exist.File 'C:/Projekte/ET/ts/customer.tsx' does not exist.File 'C:/Projekte/ET/ts/customer.d.ts' does not exist.Directory 'C:/Projekte/ET/ts/customer' does not exist, skipping all lookups in it.Loading module as file / folder, candidate module location 'C:/Projekte/ET/ts/customer', target file type 'JavaScript'.File 'C:/Projekte/ET/ts/customer.js' does not exist.File 'C:/Projekte/ET/ts/customer.jsx' does not exist.Directory 'C:/Projekte/ET/ts/customer' does not exist, skipping all lookups in it.======== Module name './customer' was not resolved. ========
import {Cust} from './customer';
Modulauflösung (absolut)
File Main.ts:
File 'C:/Projekte/ET/ts/node_modules/customer.ts' does not exist.File 'C:/Projekte/ET/ts/node_modules/customer.tsx' does not exist.File 'C:/Projekte/ET/ts/node_modules/customer.d.ts' does not exist.Directory 'C:/Projekte/ET/ts/node_modules/@types' does not exist, skipping all lookups in it.Directory 'C:/Projekte/ET/node_modules' does not exist, skipping all lookups in it.Directory 'C:/Projekte/node_modules' does not exist, skipping all lookups in it.Directory 'C:/node_modules' does not exist, skipping all lookups in it.Loading module 'customer' from 'node_modules' folder, target file type 'JavaScript'.File 'C:/Projekte/ET/ts/node_modules/customer.js' does not exist.File 'C:/Projekte/ET/ts/node_modules/customer.jsx' does not exist.Directory 'C:/Projekte/ET/node_modules' does not exist, skipping all lookups in it.Directory 'C:/Projekte/node_modules' does not exist, skipping all lookups in it.Directory 'C:/node_modules' does not exist, skipping all lookups in it.======== Module name 'customer' was not resolved. ========
import {Cust} from 'customer';
SystemJS: Textdateien importieren 1/2
System.config({
map: {
text:
'path/to/text.js'
}
});
import myText from './mytext.html!text';
SystemJS: Textdateien importieren 1/2
tsconfig.json
{
"compilerOptions": {
"sourceMap": true,
"module": "system",
"target": "es5",
"strictNullChecks": true,
"alwaysStrict": true
},
"exclude": [
"node_modules",
"jspm_packages",
"**/*.spec.ts"
]
}
package.json (Ausschnitt)
{
"jspm": {
"dependencies": {
"systemjs":
"npm:systemjs@^0.19.25",
"text":
"github:systemjs/plugin-text@^0.0.9"
},
"devDependencies": {
"jspm": "0.16.34"
}
}
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
TSConfig – Meine Empfehlung
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"noImplicitThis": false,
"strict": true
}
}
Erzeugbar über: tsc -init Seit TypeScript 2.3
Agenda
Status quo, Editor Support
Advanced Variables, Interfaces and Classes
Advanced Types
Async / Await
Decorators und Mixins
Module Resolution
Projektsetup
Erste Hilfe
VS-Code TypeScript-Version:
TypeScript-Version:tsc –v
Suchpfad überprüfenwhere tsc
TypeScript wächst
TypeScript für Fortgeschrittene
JavaScript that scales
Great tooling enabled by static types
Features from the future today
Vielen Dank
Blog: http://blog.bridging-it.de/author/Tobias.Meier
Email: Tobias.Meier@bridging-it.de
Twitter: @bITTobiasMeier
Bilder: www.dreamstime.com