Generics in TypeScript
Dit artikel legt uit wat generics in TypeScript zijn.
YouTube Video
Generics in TypeScript
Generics in TypeScript is een functie waarmee je herbruikbare en type-veilige functies, klassen en interfaces kunt definiëren door typen te parametriseren. Door generics te gebruiken, kun je code schrijven die niet afhankelijk is van specifieke typen, zodat je dezelfde bewerkingen op verschillende typen kunt uitvoeren.
De basisprincipes van Generics
Generics werken als sjablonen die typen als argumenten accepteren, zodat functies en klassen met verschillende typen kunnen werken.
Generieke functies
Het volgende is een voorbeeld van een functie waarbij de argumenttypen worden gespecificeerd met behulp van 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
is een generiek typeargument dat de typen van de argumenten en de retourneerwaarde van de functie vertegenwoordigt. Het daadwerkelijke type wordt bepaald op het moment dat de functie wordt aangeroepen.- Door expliciet
<number>
of<string>
op te geven, specificeer je het type.
Generieke typen werken ook zonder expliciete specificatie, omdat TypeScript type-inferentie uitvoert.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
- Zelfs zonder expliciet
<number>
of<string>
te specificeren, vindt type-inferentie plaats.identity(42)
wordt afgeleid alsnumber
, enidentity("Hello")
wordt afgeleid alsstring
.
Beperkingen op Generics
Door beperkingen op generics te plaatsen, kun je ze beperken tot het accepteren van alleen specifieke typen.
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.
- Het specificeren van
T extends { length: number }
geeft aan datT
een type met eenlength
-eigenschap moet zijn. Daarom worden typen zonder eenlength
-eigenschap niet geaccepteerd.
Combinatie met keyof
Door generics te combineren met keyof
, kun je op een type-veilige manier de namen van eigenschappen verkrijgen.
1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2 return obj[key];
3}
4
5const person = { name: "Bob", age: 30 };
6const personName = getProperty(person, "name"); // string
7console.log(personName);
8
9// const error = getProperty(person, "unknown"); // Error
K
wordt beperkt doorkeyof T
, wat betekent dat alleen bestaande sleutels inT
kunnen worden opgegeven. Het opgeven van een niet-bestaande sleutel zal resulteren in een compileerfout.
Generieke klassen
Klassen kunnen ook worden gedefinieerd met behulp van generics. Generieke klassen bieden flexibele typen voor eigenschappen en methoden.
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>
verklaart het typeT
dat binnen de klasse wordt gebruikt als een generiek type. Dit maakt het mogelijk om dezelfde klasse opnieuw te gebruiken voor verschillende typen.
Generieke interfaces
Generics kunnen ook worden gebruikt met interfaces.
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 ] }
- Door twee generieke typen te specificeren met
Pair<T, U>
, kun je een object definiëren met een combinatie van verschillende typen.
Standaardtype Argumenten
Het is ook mogelijk om een standaardtype voor generieke type-argumenten op te geven.
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]
- We stellen het standaardtype-argument in op
string
met<T = string>
. Als er geen type expliciet wordt opgegeven, zalT
van het typestring
zijn.
Generieke Type-Aliassen
Generieken kunnen ook worden gebruikt als type-aliasen (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>
vertegenwoordigt een resultaatobject dat gegevens van het typeT
bevat. Op deze manier kun je flexibele type-aliasen maken met behulp van generieken.
Meerdere Generieke Types
Door gebruik te maken van meerdere generieke types kun je nog veelzijdigere functies en klassen definiëren.
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' }
- De functie
merge
neemt twee verschillende typesT
enU
en combineert deze om een nieuw object te retourneren.
Samenvatting
- Generieken maken herbruikbare en type-veilige code mogelijk door types als parameters te behandelen.
- Door generieken te gebruiken in functies, klassen en interfaces, kun je flexibele logica schrijven die verschillende types verwerkt.
- Door beperkingen aan type-argumenten toe te voegen of standaardtype argumenten in te stellen, kun je de reikwijdte van generieken beheersen.
Door gebruik te maken van generieken, kun je type-onafhankelijke, algemene code schrijven en optimaal profiteren van TypeScript's krachtige type-systeem.
Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.