Learning Ionic | Tag 3: Grundlagen TypeScript

Heute lernen wir Javascript und Typescript kennen. Wir arbeiten mit den Grundelementen und erstellen einfache Programme. Am Ende gibts es wieder ein paar Übungen und Fragen

Erste Schritte

Die nachfolgenden Beispiele setzen auf eine vorhandene Ionic App auf. Als Beispiel erstellen wir eine App basierend auf der Vorlage sidemenu.

Ionic vorbereiten und App erstellen

npm i -g ionic
.../bin/ionic -> .../lib/node_modules/ionic/bin/ionic
+ ionic@4.5.0
added 10 packages from 3 contributors, removed 2 packages and updated 12 packages in 39.52s
ionic --version
4.5.0
ionic start StartingWithTypescript sidemenu --type angular --no-link

App starten 

ionic serve --lab

Typescript Grundlagen

Was ist den Typescript genau?

Typescript ist eine Programmiersprache, die ähnlich wie JavaScript funktioniert. Sie schreiben Ihren Code in Typescript und dieser wird nach JavaScript kompiliert. Damit ist das Resultat auf Browsern lauffähig.

Zudem zeigt Ihnen Typescript Fehler an, falls Sie einen Wert falschen Typs eingegeben haben.

Typescript mit seinen Möglichkeiten

  1. Typescript basiert und erweitert Javascript. Damit laufen Typescript-Programme auf jedem JavaScript-fähigen Browser.
  2. Das besondere an Typescript ist, dass das statische Typensystem nur optional ist. Wer will, kann nicht nur statisch oder dynamisch schreiben, sondern sogar beide Codearten mischen.
  3. In Programmteilen mit einem falschem Typen weißt Sie Typescript sofort auf dieses Problem hin.

Vereinfacht: Typescript ist ein verbessertes Javascript mit einer Vielzahl von Möglichkeiten, um Fehler zu vermeiden oder im Vorfeld bereits zu erkennen.

Hier ein einfaches Beispiel (von dieser Seite übernommen)

function greeter(person: string) {
    return "Hello, " + person;
}

let user = "Jane User";

document.body.innerHTML = greeter(user);

Grundlegende Elements

Weiteres Informationen findet ihr hier und hier.

Variablen und Typen

Variablen werden verwendet, Werte und Informationen zu speichert, Typen legen fest, wie diese Werte aussehen, z. B. Text, Zahl oder Datum


Basistypen

Es gibt 3 Basistypen in TypeScript: booleannumber und string

let isDone: boolean = false;
let age: number = 42;
let name: string = "Mustermann";

Der Typ kann entfallen, wenn er aus dem Wert abgeleitet werden kann

let isDone = false;
let age = 42;
let name = "Mustermann";

Ist der Typ nicht bekannt, dann wird der Typ any verwendet

let notSure: any = 4;
notSure = "eventuell eine Zeichenkette";
notSure = false; // okay, ein wahrheitswert boolean)

Um einen konstanten Wert zu definieren wird const verwendet.

Der Wert kann danach nicht mehr verändert werden

const numLivesForCat = 9;
numLivesForCat = 1; // FEHLER

Arrays

For collections, there are typed arrays and generic arrays

let list: number[] = [1, 2, 3];

Alternativ kann auch die folgende Schreibweise verwendet werden (generic array type)

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

Aufzählungen begrenzen den Wert auf die in der Liste angegebenen Möglichkeiten 

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

Funktionen

void wird verwendet, wenn (z. B. bei einer Funktion kein Wert zurückgegeben wird

function sayHello(): void {
    alert("Hello");
}

The following are equivalent, the same signature will be inferred by the compiler, and same JavaScript will be emitted

let f = function (i: number): number { return i * i; }

Return type inferred

let f = function (i: number) { return i * i; }

„Fat arrow“ syntax

let f = (i: number): number => { return i * i; }

„Fat arrow“ syntax with return type inferred

let f = (i: number) => { 
    return i * i; 
}

„Fat arrow“ syntax with return type inferred, braceless means no return keyword needed

let f = (i: number) => i * i;

Interface

Interfaces are structural, anything that has the properties is compliant with the interface

interface Person {
  name: string;
  // Optional properties, marked with a "?"
  age?: number;
  // And of course functions
  move(): void;
}

Objekte

Object that implements the „Person“ interface can be treated as a Person since it has the name and move properties

let p: Person = { 
    name: "Bobby", 
    move: () => { } 
};

Objects that have the optional property

let invalidPerson: Person = {
    name: "Bobby", 
    age: true
};

Is not a person because age is not a number

let invalidPerson: Person = {
    name: "Bobby",
    age: true
};

Interfaces can also describe a function type

interface SearchFunc {
    (
        source: string, 
        subString: string
    ): boolean;
}

Only the parameters‘ types are important, names are not important.

let mySearch: SearchFunc;
mySearch = function(
        src: string, 
        sub: string
    ) {
  return src.search(sub) != -1;
}

Klasse

Definition der Klasse

class Point {

Classes – members (Properties) are public by default

    x: number;

Constructor – the public/private keywords in this context will generate the boiler plate code for the property and the initialization in the constructor.
In this example, „y“ will be defined just like „x“ is, but with less code

Default values are also supported

    constructor(
        x: number, 
        public y: number = 0
    ) {
    this.x = x;
  }

Functions

    dist() { 
    return Math.sqrt(this.x * this.x + this.y * this.y);
    }

Static members

  static origin = new Point(0, 0);

Ende der Definition der Klasse

}

Classes can be explicitly marked as implementing an interface.
Any missing properties will then cause an error at compile-time.

class PointPerson implements Person {
    name: string
    move() {}
}

let p1 = new Point(10, 20);
let p2 = new Point(25); //y will be 0

// Inheritance
class Point3D extends Point {
  constructor(x: number, y: number, public z: number = 0) {
    super(x, y); // Explicit call to the super class constructor is mandatory
  }

  // Overwrite
  dist() {
    let d = super.dist();
    return Math.sqrt(d * d + this.z * this.z);
  }
}

Module

Modules, „.“ can be used as separator for sub modules

module Geometry {
  export class Square {
    constructor(public sideLength: number = 0) {
    }
    area() {
      return Math.pow(this.sideLength, 2);
    }
  }
}

let s1 = new Geometry.Square(5);

Local alias for referencing a module

import G = Geometry;
let s2 = new G.Square(10);

Generics

Generics: Classes

class Tuple<T1, T2> {
  constructor(public item1: T1, public item2: T2) {
  }
}

Generics: Interfaces

interface Pair<T> {
  item1: T;
  item2: T;
}

Generics: Functions

let pairToTuple = function <T>(p: Pair<T>) {
  return new Tuple(p.item1, p.item2);
};

let tuple = pairToTuple({ item1: "hello", item2: "world" });

References

Including references to a definition file:

/// <reference path="jquery.d.ts" />

Template Strings (strings that use backticks)
String Interpolation with Template Strings

Multiline Strings with Template Strings

let name = 'Tyrone';
let greeting = `Hi ${name}, how are you?`
let multiline = `This is an example
of a multiline string`;

Interfaces mit Read-Only

READONLY: New Feature in TypeScript 3.1

interface Person {
  readonly name: string;
  readonly age: number;
}

Error, p1.x is read-only

var p1: Person = { name: "Tyrone", age: 42 };
p1.age = 25;

READONLY: New Feature in TypeScript 3.1

var p2 = { name: "John", age: 60 };

Ok, read-only alias for p2

var p3: Person = p2; // 

Error, p3.x is read-only

p3.x = 35;

Ok, but also changes p3.x because of aliasing

p2.x = 45; // 

Zuweisungen sind im constructor erlaubt

class Car {
  readonly make: string;
  readonly model: string;
  readonly year = 2018;

  constructor() {
    this.make = "Unknown Make"; 
    this.model = "Unknown Model";
  }

Arrays

Definition eines Arrays

let numbers: Array<number> = [0, 1, 2, 3, 4];
let moreNumbers: ReadonlyArray<number> = numbers;

Fehler: Elemente sind read-only

moreNumbers[5] = 5;

Fehler: Array ist read-only

moreNumbers.push(5);
moreNumbers.length = 3;
numbers = moreNumbers;

Unsere App

Nachfolgend werden wir nun unsere Beispiel-App genauer betrachten und die einzelnen Dateien und Programmteil besprechen

Den relevante Teil in Bezug auf die Programmierung mit Typescript finden wir in der Datei list.page.ts

list.page.ts

export class ListPage implements OnInit {
	private selectedItem: any;
	private icons = [
		'flask',
		'wifi',
		'beer',
		'football',
		'basketball',
		'paper-plane',
		'american-football',
		'boat',
		'bluetooth',
		'build'
	];
	public items: Array<{ title: string; note: string; icon: string }> = [];
	constructor() {
		for (let i = 1; i < 11; i++) {
			this.items.push({
				title: 'Item ' + i,
				note: 'This is item #' + i,
				icon: this.icons[Math.floor(Math.random() * this.icons.length)]
			});
		}
	}

	ngOnInit() {}
	// add back when alpha.4 is out
	// navigate(item) {
	//   this.router.navigate(['/list', JSON.stringify(item)]);
	// }
}

list.page.ts im Detail

Definition der Klasse ListPage

export class ListPage implements OnInit {

Definition einer internen Variablen selectedItem

private selectedItem: any;

Definition des Array icons mit den verschiedenen Namen der Icons

private icons = [
    'flask',
    'wifi',
    'beer',
    'football',
    'basketball',
    'paper-plane',
    'american-football',
    'boat',
    'bluetooth',
    'build'
];	

Definition des Arrays items, das die anzuzeigenden Einträge beinhalten soll.

Das Array wird hier nur definiert, der Inhalt wird in nachfolgendem Programmteil (constructor) durchgeführt.

public items: Array<{ 
    title: string; 
    note: string; 
    icon: string
}> = [];

Der constructor wird verwendet, wenn ein neues Objekt dieser Klasse erstellt wird: er führt die Initialisierung durch.

Hier wird in einer Schleife (1..10) das Array items mit den gewünschten Werten gefüllt.

this.items.push fügt dem Array am Ende einen neuen Wert hinzu.

constructor() {
    for (let i = 1; i < 11; i++) {
        this.items.push({
	title: 'Item ' + i,
	note: 'This is item #' + i,
	icon: this.icons[
        Math.floor(Math.random() * this.icons.length)
        ]
	});
    }
}

Die Funktion ngOnInit wird aufgerufen, wenn die Seite das erste Mal angezeigt wird.

ngOnInit() {}

Die Funktion navigate soll verwendet werden, um bei einem Klick auf einen Listeneintrag auf die entsprechende Seite weiter zu navigieren.

// add back when alpha.4 is out
// navigate(item) {
//  this.router.navigate([
//        '/list',
//        JSON.stringify(item)
//    ]);
// }

Dies beendet die Definition der Klasse ListPage

}

Beispiele

Variablen: Zeilen und Zeichenfolgen

Wir definieren eine neue Variable name.

export class HomePage {
    public name: string;
        constructor() {
            this.name="Erster Text";
        }
}