Читать книгу Angular - Manfred Steyer - Страница 45

Generics

Оглавление

Nicht immer lässt sich im Voraus ein Datentyp festlegen. Generische Klassen, kurz Generics, helfen in solchen Situationen. Sie erhalten Typparameter für jene Datentypen, die beim Schreiben der Klasse nicht bekannt sind. Diese Typparameter können Sie verwenden wie andere Datentypen auch. Erst wenn die Klasse instanziiert wird, ist für diese Typparameter ein konkreter Datentyp anzugeben.

Bei der Klasse Invoice in Beispiel 2-24 handelt es sich um solch ein Generic.

Beispiel 2-24: Generische Klasse

// src/app/ts/invoice.ts

export class Invoice<T> {

constructor(readonly subject: T, readonly price: number) {

}

toString(): string {

let id = '';

// id = this.subject.id; // Fehler

return `${id}: ${this.price}`;

}

}

Sie definiert einen Typparameter T im Anschluss an den Klassennamen und nutzt diesen zur Typisierung der Eigenschaft subject.

Ein Problem gibt es hier jedoch in der Methode toString: Der Compiler verbietet den Zugriff auf this.subject.id. Der Typparameter T kann zur Laufzeit ja alles Mögliche sein, und deswegen kann der Compiler nicht garantieren, dass dann eine Eigenschaft id vorliegt.

Abhilfe schafft hier eine Einschränkung für den Typparameter. Die Klasse Flight Invoice in Beispiel 2-25 gibt beispielsweise mit extends Flight an, dass der Typparameter T ein Flight oder eine Subklasse davon sein muss:

Beispiel 2-25: Generische Klasse mit Einschränkung für Typparameter

// src/app/ts/flight-invoice.ts

import { Flight } from '../flight';

export class FlightInvoice<T extends Flight> {

constructor(readonly subject: T, readonly price: number) {

}

toString(): string {

const id = this.subject.id; // Klappt nun!

return `${id}: ${this.price}`;

}

}

Aufgrund dieser Einschränkung garantiert TypeScript Zugriff auf alle Felder, die ein Flight mit sich bringt. Dazu gehört auch die id.

Beim Instanziieren eines Generic ist der gewünschte Datentyp anzugeben. Ein Beispiel dafür findet sich in Beispiel 2-26, das T auf CharterFlight festlegt:

Beispiel 2-26: Nutzung einer generischen Klasse

// src/app/ts/demo.ts

import { CharterFlight } from './charter-flight';

import { FlightInvoice } from './flight-invoice';

[...]

const charterFlightToCharge = new CharterFlight();

charterFlightToCharge.from = 'Graz';

charterFlightToCharge.to = 'Hamburg';

charterFlightToCharge.distance = 1000;

const price = charterFlightToCharge.calcPrice();

const charterInvoice = new FlightInvoice<CharterFlight>(charterFlightToCharge, price);

console.debug('charterInvoice', charterInvoice.toString());

Neben Typen wie Klassen lassen sich auch Funktionen sowie Methoden generisch gestalten:

function min<T>(a: T, b: T): T {

if (a < b) {

return a;

}

return b;

}

In diesem Fall ist gewährleistet, dass die beiden Übergabeparameter sowie der Rückgabewert vom selben Typ sind. Beim Aufruf können Sie nun einen konkreten Datentyp für den festgelegten Typparameter T angeben:

const r1 = min<number>(1, 2); // 1

In vielen Fällen kann TypeScript den Datentyp des Typparameter jedoch aus dem Aufruf ableiten. Somit können Sie häufig die Angabe des Datentyps weglassen:

const r2 = min(1, 2); // 1

const r3 = min('a', 'b'); // 'a'

Angular

Подняться наверх