Geavanceerde generieke functies van TypeScript uitgelegd met voorbeelden

Generics in TypeScript bieden een manier om herbruikbare en flexibele codecomponenten te maken door met verschillende gegevenstypen te werken. Geavanceerde generics nemen dit concept verder door extra functies te introduceren, zoals beperkingen, standaardwaarden en meerdere typen, waarmee ontwikkelaars robuustere en typeveiligere code kunnen schrijven. In dit artikel worden voorbeelden gebruikt om deze geavanceerde concepten in generics te verkennen.

Algemene beperkingen

Beperkingen beperken de typen die een generiek type kan accepteren. Dit zorgt ervoor dat het type dat aan een generieke functie of klasse wordt doorgegeven, aan bepaalde criteria voldoet. Een beperking kan bijvoorbeeld worden gebruikt om ervoor te zorgen dat het generieke type een specifieke eigenschap of methode heeft.

function getLength<T extends { length: number }>(arg: T): number {
    return arg.length;
}

const stringLength = getLength("TypeScript");
const arrayLength = getLength([1, 2, 3]);

In dit voorbeeld zorgt de beperking <T extends { length: number }> ervoor dat het argument dat wordt doorgegeven aan getLength de eigenschap length heeft.

Meerdere generieke varianten

TypeScript staat het gebruik van meerdere generieke typen in dezelfde functie, klasse of interface toe. Dit is handig bij het werken met paren van waarden of andere datastructuren met meerdere typen.

function pair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

const stringNumberPair = pair("TypeScript", 2024);

Deze functie, pair, accepteert twee verschillende generieke typen, T en U, en retourneert een tuple die beide typen bevat.

Standaard generieke typen

Generics in TypeScript kunnen ook standaardtypen hebben. Dit is handig als u wilt dat een generic een fallback-type heeft als er geen specifiek type is opgegeven.

function identity<T = string>(value: T): T {
    return value;
}

const defaultString = identity("Hello");  // T is string
const customNumber = identity<number>(100);  // T is number

In dit voorbeeld wordt standaard string gebruikt als er geen type wordt doorgegeven aan identity.

Generics gebruiken met interfaces

Generics kunnen worden gebruikt met interfaces om complexe structuren te definiëren waar typen niet vastliggen. Dit voegt flexibiliteit toe aan hoe data wordt beheerd.

interface Container<T> {
    value: T;
}

const stringContainer: Container<string> = { value: "Hello" };
const numberContainer: Container<number> = { value: 42 };

De interface Container is ontworpen om een ​​waarde van elk type te bevatten, waardoor verschillende soorten containers met specifieke typen mogelijk zijn.

Algemene klassen

Klassen in TypeScript kunnen ook generiek zijn. Dit is vooral handig bij het ontwerpen van klassen die werken met verschillende gegevenstypen, zoals gegevensopslag- of verzamelingsklassen.

class DataStore<T> {
    private data: T[] = [];

    add(item: T): void {
        this.data.push(item);
    }

    getAll(): T[] {
        return this.data;
    }
}

const stringStore = new DataStore<string>();
stringStore.add("Hello");
stringStore.add("TypeScript");

const numberStore = new DataStore<number>();
numberStore.add(42);

In dit voorbeeld werkt de klasse DataStore met elk type gegevens en biedt een typeveilige manier om elementen op te slaan en op te halen.

Conclusie

Geavanceerde generics in TypeScript zijn een krachtig hulpmiddel voor het schrijven van flexibele, herbruikbare en type-safe code. Door gebruik te maken van beperkingen, meerdere typen, standaardwaarden en generics in klassen en interfaces, kunnen ontwikkelaars complexere en robuustere code schrijven. Het begrijpen en gebruiken van deze geavanceerde concepten zorgt voor meer flexibiliteit en garandeert type safety in alle applicaties.