Generice de bază în TypeScript
Genericele îți permit să creezi „variabile de tip” — substituenți pentru un tip care este completat mai târziu. Le poți folosi în clase, funcții și aliasuri de tip, astfel încât acestea să nu fie nevoite să numească tipurile exacte cu care lucrează.
Genericele fac mai ușoară scrierea de cod care poate fi reutilizat cu multe tipuri diferite.
Funcții
Funcțiile generice sunt mai generale: ele funcționează cu orice tip, descriind în același timp cu exactitate tipurile de intrare și de retur.
Notă: TypeScript poate, de asemenea, să deducă parametrii de tip generici din argumentele pe care le transmiți, așa că de multe ori nu este nevoie să îi scrii explicit.
Exemplu
S și T sunt variabile de tip. Apelul le completează ca string și number, așa că rezultatul are tipul [string, number].
createPair<S, T> care primește v1: S și v2: T și returnează tuplul [S, T], apoi afișează createPair<string, number>('hello', 42) astfel încât rezultatul să fie tabloul [ 'hello', 42 ].
Ieșire: program TypeScript și rezultatul capturat
function createPair<S, T>(v1: S, v2: T): [S, T] {
return [v1, v2];
}
console.log(createPair<string, number>('hello', 42)); // ['hello', 42]
Clase
Genericele pot face generală și o clasă, precum Map, clasa integrată care funcționează cu orice tipuri de chei și de valori.
Notă: TypeScript poate deduce parametrul de tip generic al unei clase atunci când acesta este folosit într-un parametru al constructorului.
Exemplu
NamedValue<number> face ca T să fie number, așa că setValue acceptă doar numere.
NamedValue<T> cu un câmp privat _value: T | undefined, un constructor care primește private name: string, setValue(value: T), getValue(): T | undefined și un toString() care returnează „name: value”; creează new NamedValue<number>('myNumber'), setează valoarea la 10 și afișează toString(), obținând „myNumber: 10”.
Ieșire: program TypeScript și rezultatul capturat
class NamedValue<T> {
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
let value = new NamedValue<number>('myNumber');
value.setValue(10);
console.log(value.toString()); // myNumber: 10
Aliasuri de tip
Genericele în aliasurile de tip îți permit să creezi tipuri care pot fi reutilizate cu multe tipuri interioare diferite.
Notă: La fel funcționează și pentru interfețe, cu sintaxa interface Wrapped<T> {
Sintaxa unui alias de tip generic
Wrapped<T> este un tip de obiect al cărui value are tipul pe care îl transmiți, de exemplu number.
type Wrapped<T> = { value: T };
const wrappedValue: Wrapped<number> = { value: 10 };
Valoare implicită
Un parametru de tip generic poate avea o valoare implicită. Valoarea implicită este folosită atunci când nu se dă niciun tip și niciunul nu poate fi dedus.
Parametru de tip implicit
T = string înseamnă că new NamedValue('myNumber'), fără un argument de tip, folosește string pentru T.
class NamedValue<T = string> {
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
let value = new NamedValue('myNumber');
value.setValue('myValue');
console.log(value.toString()); // myNumber: myValue
Extends
Poți adăuga restricții unui generic pentru a limita tipurile permise.
O restricție îți permite să te bazezi pe un tip mai specific atunci când folosești variabila de tip.
Notă: O restricție poate fi combinată cu o valoare implicită.
Restricționarea unui parametru de tip
S extends string | number înseamnă că pentru S pot fi transmise doar șiruri și numere, așa că valorile pot fi afișate în siguranță.
function createLoggedPair<S extends string | number, T extends string | number>(v1: S, v2: T): [S, T] {
console.log(`creating pair: v1='${v1}', v2='${v2}'`);
return [v1, v2];
}