TypeScript Grundlagen

TypeScript

TypeScript: Verbreitete Alternative zu JavaScript

Statische Typisierung → bessere Autovervollständigung und Fehlererkennung

Statische Typisierung

Datentypen können explizit vom Entwickler angegeben werden oder von der Entwicklungsumgebung abgeleitet werden (engl. type inference)

Vortile:

  • bessere Autovervollständigung
  • bessere Fehlererkennung

Statische Typisierung

Beispiel:

let names: Array<string> = [];

names.push('Alice');
names.push('Bob');

console.log(names[0].toUpperCase());

Playground

online mit TypeScript experimentieren:

https://www.typescriptlang.org/play

Build

Build

Browser verstehen nur JavaScript, nicht TypeScript

→ Code muss von TypeScript in JavaScript übersetzt werden, um im Browser zu laufen

Build

Beispielhafte Projekteinrichtung mit node / npm und vite:

npm create vite@latest

→ wähle Vanilla, dann TypeScript

Datentypen und Typendeklarationen

Datentypen

Datentypen und Deklarationen, die wir verwenden werden:

  • boolean
  • number
  • string
  • array
  • object

Variablentypen

Variablentypen können beim Deklarieren von Variablen angegeben werden:

let age: number = 32;
let age: number;
age = 32;
age++;

Type Inference

in vielen Fällen kennt TypeScript den Typ automatisch (keine Annotation notwendig):

let age = 32;

Primitive Typen

const age: number = 32;
const name: string = 'Alice';
const loggedIn: boolean = true;

Array-Typen

const names: Array<string> = [];
names.push('Alice');

alternative Schreibweise:

const names: string[] = [];
names.push('Alice');

Objekttypen

Typendeklaration:

let todo: {
  id: number;
  title: string;
  completed: boolean;
};

Zuweisung:

todo = { id: 1, title: 'foo', completed: false };

Objekttypen

optionale Einträge werden mit ? gekennzeichnet

let todo: {
  id: number;
  title: string;
  completed: boolean;
  date?: string;
};

Union Types

Variablen, die mehrere Typen annehmen können:

let width: string | number | undefined;

width = '16px';
width = 16;

Type Aliases und Interfaces

Type Aliases und Interfaces

Mit Type Aliases oder Interfaces können wir eine Typendeklaration unter einem Namen speichern

Type Aliases können etwas einfacher und flexibler sein als Interfaces (Vergleich auf StackOverflow)

Type Aliases und Interfaces

Type Alias für ein Objekt:

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

Interface für ein Objekt:

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

Verwendung von Type Aliases / Interfaces

const todos: Array<Todo> = [
  { id: 1, title: 'foo', completed: false },
  { id: 2, title: 'bar', completed: true },
];

Type Aliases und Interfaces

Type Aliases und Interfaces sollten groß geschrieben werden (z.B. Todo, nicht todo)

Funktionssignaturen und Funktionstypen

Funktionssignaturen

function shorten(text: string, maxLen: number): string {
  // ...
}
const shorten = (text: string, maxLen: number): string => {
  // ...
};

Funktionssignaturen

Funktionen ohne Rückgabewert: void

function logMessage(message: string): void {
  console.log(message);
}

Funktionstypen

Speichern einer Funktionssignatur unter einem Type Alias:

// a validator is a function that receives a string
// and returns a boolean
type Validator = (s: string) => boolean;

Anwenden der Type Alias:

const validateEmail: Validator = (s) => s.includes('@');

const validateYear: Validator = (s) => {
  return new RegExp('^d{4}$').test(s);
};

Generics

Generics

Generic: allgemeine Typendeklaration, zu der bei der Anwendung nähere Informationen spezifiziert werden können (via <...>)

Generics

Beispiel: Array ist ein Generic

const names: Array<string> = ['Alice', 'Bob', 'Charlie'];

Generics

Beispiel: Promise ist ein Generic

type User = { username: string; picture: string };

async function fetchUser(): Promise<User> {
  // ...
}

Type Assertions

Type Assertions

Bei Funktionsaufrufen, die auf "externe" Ressourcen zugreifen kann TypeScript alleine oft nicht den Typ bestimmen.

Beispiele:

  • fetch()
  • JSON.parse()
  • document.getElementById()

Type Assertions erlauben es uns, ein bestehendes Objekt als einen bestimmten Typ zu behandeln

Type Assertions

dies schlägt fehl:

// TypeScript type: HTMElement or null
const nameInput = document.getElementById('name-input');
// error: nameInput is possibly null
console.log(nameInput.id);
// error: nameInput is possibly null
console.log(nameInput.value);

Type Assertions

"Assertion", dass ein Wert nicht null oder undefined ist mittels "!":

// TypeScript type: HTMLElement
const nameInput = document.getElementById('name-input')!;
// works
console.log(nameInput.id);
// error: property `value` does not exist on type `HTMLElement`
console.log(nameInput.value)

Type Assertions

"Assertion", dass ein Wert einen bestimmten Typ hat mittels "as":

const nameInput = document.getElementById(
  'name-input'
) as HTMLInputElement;
// works
console.log(nameInput.id);
// works
console.log(nameInput.value);

(Bemerkung: HTMLInputElement ist eine Unterklasse von HTMLElement)

Type Assertions

Beispiel: Fetchen von JSON-Daten

type User = { username: string; picture: string };

async function fetchUser(): Promise<User> {
  const res = await fetch('/api/user');
  if (!res.ok) {
    throw new Error('fetch failed');
  }
  const user = (await res.json()) as User;
  return user;
}