Generics i TypeScript

Generics i TypeScript

Denne artikkelen forklarer generics i TypeScript.

YouTube Video

Generics i TypeScript

Generics i TypeScript er en funksjon som lar deg definere gjenbrukbare og typesikre funksjoner, klasser og grensesnitt ved å parameterisere typer. Ved å bruke generics kan du skrive kode som ikke er avhengig av spesifikke typer, og dermed utføre de samme operasjonene på ulike typer.

Grunnleggende om Generics

Generics fungerer som maler som aksepterer typer som argumenter, og gjør det mulig for funksjoner og klasser å håndtere ulike typer.

Generiske Funksjoner

Følgende er et eksempel på en funksjon der argumenttypene er angitt ved hjelp av generics.

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity<number>(42));       // 42
6console.log(identity<string>("Hello"));  // Hello
  • T er et generisk typeargument som representerer typene til funksjonens argumenter og returverdi. Den faktiske typen bestemmes når funksjonen kalles.
  • Ved eksplisitt å spesifisere <number> eller <string>, spesifiserer du typen.

Generiske typer fungerer uten eksplisitt spesifikasjon fordi TypeScript utfører typeinferens.

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

Begrensninger på Generics

Ved å legge begrensninger på generics kan du begrense dem til å akseptere kun spesifikke 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.
  • Å spesifisere T extends { length: number } indikerer at T må være en type med en length-egenskap. Dermed vil typer uten en length-egenskap ikke bli akseptert.

Generiske Klasser

Klasser kan også defineres ved hjelp av generics. Generiske klasser gir fleksible typer for egenskaper og 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> erklærer typen T brukt i klassen som en generic. Dette gjør at samme klasse kan brukes om igjen for forskjellige typer.

Generiske Grensesnitt

Generics kan også brukes med grensesnitt.

 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 ] }
  • Ved å spesifisere to generiske typer med Pair<T, U>, kan du definere et objekt med en kombinasjon av ulike typer.

Standardtypargumenter

Det er også mulig å spesifisere en standardtype for generiske typeargumenter.

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 setter standardtypeargumentet til string med <T = string>. Hvis ingen type er spesifisert eksplisitt, vil T være av typen string.

Generiske typealiaser

Generiske typer kan også brukes som typealiaser (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> representerer et resultatobjekt som inneholder data av typen T. På denne måten kan du lage fleksible typealiaser ved hjelp av generiske typer.

Flere generiske typer

Ved å bruke flere generiske typer kan du definere enda mer allsidige funksjoner og 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-funksjonen tar to forskjellige typer T og U og kombinerer dem for å returnere et nytt objekt.

Sammendrag

  • Generics muliggjør gjenbrukbar og typesikker kode ved å behandle typer som parametere.
  • Ved å bruke generiske typer i funksjoner, klasser og grensesnitt, kan du skrive fleksibel logikk som håndterer forskjellige typer.
  • Ved å legge til begrensninger på typeargumenter eller sette standardtypeargumenter, kan du kontrollere omfanget av generiske typer.

Ved å bruke generiske typer kan du skrive typeuavhengig og generell kode, og utnytte TypeScripts kraftige typesystem fullt ut.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video