22. Januar 2022

| Timm Rose

TypeScript lernen: Grundlagen

22. Januar 2022

| Timm Rose

TypeScript lernen: Grundlagen

1. Was ist TypeScript

TypeScript ist eine typsichere Obermenge von JavaScript und erweitert dieses um ein statisches Typsystem. Es wird ein TypeScript-Compiler benötigt, der den Code in JavaScript übersetzt.

Entwickelt wurde die Sprache bei Microsoft von Anders Hejlsberg, der als Miterfinder des .NET-Systems und Hauptentwickler der Programmiersprachen C# und eben TypeScript bekannt ist.

Vorteile von TypeScript

Eine Auflistung der wesentlichen Vorteile von TypeScript:

  • die frühzeitige Erkennung von Laufzeitfehlern, sodass Fehler im Code bereits vor der Laufzeit erkannt werden können
  • Unterstützung beim Refactoring des Sourcecodes
  • bessere Codevervollständigung und Syntaxprüfung

Weitere Merkmale die TypeScript mit sich bringt, sind

2. Sprachkern

Variablen

let

Variablen die mit dem Schlüsselwort let deklariert (Deklaration) werden, sind zum Beispiel im Kontext einer Funktion für einen Block gültig. Eine mit let deklarierte Variable enthält den Namen und danach per Doppelpunkt getrennt, den Typ

let city: string;

Möchtest du die Variable direkt mit einem Wert initialisieren, kannst du diesen direkt hinter den Typ schreiben. Hier erfolgt die Zuweisung mit dem Zuweisungsoperator (Gleichheitszeichen)

let city: string = 'Stockholm';

Typinferenz

Deklaration und Initialisierung kannst du auch kompakt in eine Zeile schreiben. Hier versucht TypeScript den Typ abzuleiten, deshalb spricht man hier auch von Typinferenz

let city = 'Stockholm';

const

Mit dem Schlüsselwort const werden Konstanten deklariert. Damit kannst du Variablen deklarieren, deren Wert nicht mehr änderbar ist, sie können später nicht mehr überschrieben werden.

Für Konstanten gelten die gleichen Konzepte, wie zum Beispiel die der Typinferenz

const city: string = 'Kopenhagen';

var

Mit var deklarierte Variablen sind nahezu identisch wie mit let deklarierte Variablen zu verwenden

var city = 'Bröndby';

Im Kontext einer Funktion gelten sie allerdings für die gesamte Funktion, während let nur für den Block gilt

function city(citizen: number): boolean {
  // large ist in der gesamten Funktion gültig

  if(citizen < 500000) {
    // small ist nur in diesem if-Block gültig

    let small = true;
    return small;
  } else {
    var large = true;
    return large;
  }
}

Datentypen

number

Der Typ number ist eine Fließkommazahl. Eine Initialisierung kann wie folgt aussehen

const citizen: number = 380000;
const citizenAvg: number = 45.03;

Die Umwandlung in einen Typ number gelingt mit parseInt, beziehungsweise parseFloat für Fließkommazahlen. In Klammern wird der Wert im originalen Typ und kommagetrennt die Basis angegeben, im Normalfall die 10 für das Dezimalsystem.

const citizen: number = parseInt('380000', 10);

string

Mit dem Typ string kannst du Zeichenketten deklarieren. Zeichenketten werden mit genau diesem Schlüsselwort und dem jeweiligen Wert in einfachen Anführungsstrichen deklariert

const citizenship: string = 'of the european union';

Auch mit Template Strings kannst du Zeichenketten erstellen. Dazu verwendest du Backticks, innerhalb derer man auch Platzhalter für Eigenschaften per Interpolation schreiben kann

const name: string = 'european';
const citizenship: string = `citizen of the ${name} union`;

boolean

Ein Wahrheitswert wird mit dem Schlüsselwort boolean deklariert. Die Werte sind true für wahr und false für unwahr

const large: boolean = true;

array

In einem Array lassen sich Werte auch unterschiedlichen Typs speichern. In diesem Fall drei Zeichenketten, die als String-Array deklariert werden

const cities: string[] = ['Helsinki', 'Göteborg', 'Oslo'];

any

Der Datentyp any kann Werte aller Typen annehmen. Du kannst ihn verwenden, wenn du noch unsicher bist, welchen Typ du hier erhalten wirst.

function

Auch der Typ function ist ein Datentyp und verweist auf eine Funktion

const city: Function = function() {
  console.log('Das ist eine Funktion!');
}

Interfaces

Mit Interfaces kannst du Strukturen eines Objektes abbilden. Die Eigenschaften werden mit ihren entsprechenden Datentypen beschrieben.

Das Schlüsselwort export ermöglicht dir den Zugriff des Interfaces von anderen Klassen, in denen sie per Import Statement importiert werden müssen

export interface City {
  name: string;
  citizen: number;
  citizenship: string;
  large: boolean;
}

Verwendet werden Interfaces dann als Typ (hier City) in der jeweiligen Klasse für die Initialisierung eines Objektes

import { City } from 'city.ts';

const city: City = {
  name: 'Goteborg',
  citizen: 572799,
  citizenship: 'Sweden',
  large: true
}

city.name = 'Helsinki';

console.log(city.name);

Klassen

Klassen kannst du wie Interfaces mit dem Schlüsselwort export und in dem Fall mit class erstellen.

Als erstes wird der Konstruktor verwendet, der beim Erzeugen von Objekten aufgerufen wird. In diesem Beispiel wird die Eigenschaft cities mit vom Typ City erstellt, wobei City das Interface repräsentiert.

export class GeoFinder {
  constructor(private cities: City[]) { }

  find(from: string, to: string): City[] {
    const result = new Array<City>();

    for(let c of this.cities) {
      if(c.from === from && c.to === to) {
        result.push(c);  
      }
    }
    return result; 
  }
}

Vererbung

Durch die Vererbung einer Klasse übernimmt die erbende Klasse die Eigenschaften und Methoden der Basisklasse (Superklasse).

Mit dem Schlüsselwort extends definierst du die Basisklasse, von der geerbt wird

export class GeoCityFinder extends GeoFinder {
  timezone: string = 'UTC+0';
}

Generics

Weiß du noch nicht welchen konkreten Typ du verwenden wirst, kommen Generics ins Spiel.

Mit dem Typparameter T wird angegeben, dass es sich um eine Klasse mit noch nicht bekanntem Typ handelt, sie aber City oder eine Subklasse davon ist

import { City } from 'city.ts';

export class CityErected<T extends City>{
  constructor(readonly year: T) { }
  
  ...
}

Spread-Operator

Möchtest du ein Objekt modifizieren, weil du zum Beispiel den Wert einer Eigenschaft ändern möchtest, kannst du den Spread-Operator einsetzen.

const city: City = {
  name: 'Goteborg',
  citizen: 572799,
  citizenship: 'Sweden',
  large: true
}

const cityData1 = { ...city };
const cityData2 = { ...city, name: 'Madrid' };

In diesem Beispiel ist cityData1 eine unveränderte Kopie dees Objekts city und cityData2 eine geänderte, hier wurde die Eigenschaft name modifiziert.

Promises

Promises sind Datenstrukturen in der Asynchronen Programmierung. Es handelt sich genauer um Werte die asynchron übermittelt werden.

Hierbei registriert der Aufrufer einen Callback, der das Ergebnis entgegen nimmt.

In diesem Beispiel erstelle ich einen Promise, der die Funktion setTimeout() kapselt

function time(time: number): Promise<number> {
  return new Promise((resolve, reject) => {
    
    setTimeout(() => {
      resolve(time);
    }, time);

    if(time < 0) {
      reject('Error');
      return;
    }
  });
}

Wenn die Asynchrone Operation erfolgreich durchlaufen wurde, wird die resolve-Funktion aufgerufen um das Ergebnis zu übergeben.

Die reject-Funktion wird aufgerufen, wenn es einen Fehler gibt.

Zum Aufruf der time-Funtkion wird mit then() der Callback registriert, der auch Fulfillment-Handler genannt wird, der das Ergebnis enthält, wenn es vorliegt.

Mit catch() wird der Callback registriert, der auch Rejection-Handler genannt wird, der im Fehlerfall ausgeführt wird.

time(500)
  .then(result => console.log(result))
  .catch(error => console.log(error));

Async/Await

Digitale Rundschau Logo

© 2021 Digitale Rundschau | Impressum