Ograniczenia generyków (extends)

Wymaganie, żeby parametr typu spełniał określony kształt.

Na tej stronie

Przykład

#
TypeScript
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b
}

console.log(longest('HTML', 'JavaScript'))
console.log(longest([1, 2, 3], [4, 5]))
Wynik
JavaScript
[1, 2, 3]

Definicja i zastosowanie

#

Parametr typu bez ograniczeń może być czymkolwiek, więc wewnątrz funkcji nie wolno założyć, że ma jakieś pole. Zapis <T extends { length: number }> mówi: „T może być dowolnym typem, ale musi mieć pole length”.

Dzięki ograniczeniom funkcja generyczna może bezpiecznie korzystać z właściwości parametru, a kompilator odrzuci wywołania z typami, które ich nie mają.

Bardzo popularne jest połączenie z keyof: <T, K extends keyof T> gwarantuje, że drugi argument jest jednym z kluczy pierwszego obiektu.

Składnia

#
Składnia
function nazwa<T extends Warunek>(param: T) { … }

Więcej przykładów

#
Klucz, który na pewno istnieje
TypeScript
function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
  return items.map((item) => item[key])
}

const students = [
  { name: 'Ania', level: 7 },
  { name: 'Kuba', level: 3 }
]

console.log(pluck(students, 'name'))
console.log(pluck(students, 'level'))
Wynik
['Ania', 'Kuba']
[7, 3]
Wywołanie odrzucone przez ograniczenie
TypeScript
longest(10, 20)
// Błąd: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.

Dobre praktyki

#
  • Ograniczaj parametry typu tylko tak, jak wymaga tego kod funkcji. Zbyt wąskie ograniczenie zmniejsza przydatność funkcji.
  • Wzór K extends keyof T to podstawa bezpiecznych funkcji pracujących na kluczach obiektów.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.