TypeScript Advanced Generics förklaras med exempel

Generics i TypeScript ger ett sätt att skapa återanvändbara och flexibla kodkomponenter genom att arbeta med en mängd olika datatyper. Avancerade generika tar detta koncept vidare genom att introducera ytterligare funktioner som begränsningar, standardvärden och flera typer, vilket gör att utvecklare kan skriva mer robust och typsäker kod. I den här artikeln kommer exempel att användas för att utforska dessa avancerade koncept inom generika.

Generiska begränsningar

Begränsningar begränsar de typer som en generisk kan acceptera. Detta säkerställer att typen som skickas till en generisk funktion eller klass uppfyller vissa kriterier. Till exempel kan en begränsning användas för att säkerställa att den generiska typen har en specifik egenskap eller metod.

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

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

I det här exemplet säkerställer <T extends { length: number }>-begränsningen att argumentet som skickas till getLength har en length-egenskap.

Flera generika

TypeScript tillåter användning av flera generiska typer i samma funktion, klass eller gränssnitt. Detta är användbart när du arbetar med värdepar eller andra datastrukturer som involverar flera typer.

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

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

Denna funktion, par, accepterar två olika generiska typer, T och U, och returnerar en tupel som innehåller båda typerna.

Standard generiska typer

Generika i TypeScript kan också ha standardtyper. Detta är användbart när du vill att en generisk ska ha en reservtyp om ingen specifik typ tillhandahålls.

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

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

I det här exemplet, om ingen typ skickas till identitet, är den standard till sträng.

Använda generika med gränssnitt

Generika kan användas med gränssnitt för att definiera komplexa strukturer där typerna inte är fixerade. Detta ger flexibilitet till hur data hanteras.

interface Container<T> {
    value: T;
}

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

Gränssnittet Container är utformat för att hålla ett värde av vilken typ som helst, vilket möjliggör olika typer av behållare med specifika typer.

Generiska klasser

Klasser i TypeScript kan också vara generiska. Detta är särskilt användbart när du designar klasser som fungerar med olika datatyper, såsom datalagring eller insamlingsklasser.

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);

I det här exemplet fungerar klassen DataStore med alla typer av data, vilket ger ett typsäkert sätt att lagra och hämta element.

Slutsats

Avancerade generika i TypeScript är ett kraftfullt verktyg för att skriva flexibel, återanvändbar och typsäker kod. Genom att använda begränsningar, flera typer, standardvärden och generika i klasser och gränssnitt kan utvecklare skriva mer komplex och robust kod. Att förstå och använda dessa avancerade koncept möjliggör större flexibilitet och säkerställer typsäkerhet över applikationer.