Generiska typer i TypeScript

Generiska typer i TypeScript

Den här artikeln förklarar generiska typer i TypeScript.

YouTube Video

Generiska typer i TypeScript

Generiska typer i TypeScript är en funktion som gör det möjligt att definiera återanvändbara och typsäkra funktioner, klasser och gränssnitt genom att använda parametriserade typer. Genom att använda generiska typer kan du skriva kod som inte är beroende av specifika typer, vilket gör det möjligt att utföra samma operationer på olika typer.

Grundläggande om generiska typer

Generiska typer fungerar som mallar som accepterar typer som argument, vilket gör det möjligt för funktioner och klasser att hantera olika typer.

Generiska funktioner

Följande är ett exempel på en funktion där argumenttyperna specificeras med hjälp av generiska typer.

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity<number>(42));       // 42
6console.log(identity<string>("Hello"));  // Hello
  • T är ett generiskt typargument som representerar typerna för funktionens argument och returvärde. Den faktiska typen bestäms när funktionen anropas.
  • Genom att explicit ange <number> eller <string> specificerar du typen.

Generiska typer fungerar utan explicit specificering eftersom TypeScript utför typinferens.

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity(42));       // 42
6console.log(identity("Hello"));  // Hello

Begränsningar på generiska typer

Genom att sätta begränsningar på generiska typer kan du begränsa dem till att endast acceptera specifika typer.

1function loggingIdentity<T extends { length: number }>(arg: T): T {
2    console.log(arg.length);
3    return arg;
4}
5
6loggingIdentity("Hello");  // 5
7loggingIdentity([1, 2, 3]);  // 3
8
9// loggingIdentity(42);  // Error: number does not have a length property.
  • Att specificera T extends { length: number } anger att T måste vara en typ med en length-egenskap. Därför kommer typer utan en length-egenskap inte att accepteras.

Generiska klasser

Klasser kan också definieras med generiska typer. Generiska klasser erbjuder flexibla typer för egenskaper och metoder.

 1class Box<T> {
 2    private _value: T;
 3
 4    constructor(value: T) {
 5        this._value = value;
 6    }
 7
 8    public getValue(): T {
 9        return this._value;
10    }
11
12    public setValue(value: T): void {
13        this._value = value;
14    }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue());  // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue());  // Hello
  • Box<T> deklarerar typen T som används inom klassen som en generisk typ. Detta gör att samma klass kan återanvändas för olika typer.

Generiska gränssnitt

Generiska typer kan också användas med gränssnitt.

 1interface Pair<T, U> {
 2    first: T;
 3    second: U;
 4}
 5
 6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
 7console.log(numberStringPair);  // { first: 1, second: 'One' }
 8
 9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair);  // { first: true, second: [ 1, 2, 3 ] }
  • Genom att specificera två generiska typer med Pair<T, U> kan du definiera ett objekt med en kombination av olika typer.

Standardtypargument

Det är också möjligt att ange en standardtyp för generiska typargument.

1function createArray<T = string>(length: number, value: T): T[] {
2    return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a"));   // ['a', 'a', 'a']
6console.log(createArray(3, 100));   // [100, 100, 100]
  • Vi ställer in standardtypargumentet till string med <T = string>. Om ingen typ anges uttryckligen, kommer T att vara av typen string.

Generiska typalias

Generiska typer kan också användas som typalias (type).

 1type Result<T> = {
 2    success: boolean;
 3    data: T;
 4};
 5
 6const successResult: Result<number> = { success: true, data: 42 };
 7const errorResult: Result<string> = { success: false, data: "Error occurred" };
 8
 9console.log(successResult);  // { success: true, data: 42 }
10console.log(errorResult);    // { success: false, data: 'Error occurred' }
  • Result<T> representerar ett resultatobjekt som innehåller data av typen T. På detta sätt kan du skapa flexibla typalias med hjälp av generiska typer.

Flera generiska typer

Genom att använda flera generiska typer kan du definiera ännu mer mångsidiga funktioner och klasser.

1function merge<T, U>(obj1: T, obj2: U): T & U {
2    return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged);  // { name: 'Alice', title: 'Engineer' }
  • merge-funktionen tar två olika typer T och U och kombinerar dem för att returnera ett nytt objekt.

Sammanfattning

  • Generiska typer möjliggör återanvändbar och typesäker kod genom att behandla typer som parametrar.
  • Genom att använda generiska typer i funktioner, klasser och gränssnitt kan du skriva flexibel logik som hanterar olika typer.
  • Genom att lägga till begränsningar för typargument eller ange standardtypargument kan du kontrollera omfattningen av generiska typer.

Genom att använda generiska typer kan du skriva typoberoende, allmän kod som utnyttjar TypeScripts kraftfulla typsystem.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video