Wyjaśnienie zaawansowanych generyków TypeScript z przykładami
Generyki w TypeScript umożliwiają tworzenie wielokrotnego użytku i elastycznych komponentów kodu poprzez pracę z różnymi typami danych. Zaawansowane generyki rozwijają tę koncepcję, wprowadzając dodatkowe funkcje, takie jak ograniczenia, wartości domyślne i wiele typów, które pozwalają programistom pisać bardziej solidny i bezpieczny pod względem typu kod. W tym artykule przykłady zostaną wykorzystane do zbadania tych zaawansowanych koncepcji w generykach.
Ograniczenia ogólne
Ograniczenia ograniczają typy, które typ generyczny może zaakceptować. Zapewnia to, że typ przekazany do funkcji lub klasy generycznej spełnia określone kryteria. Na przykład ograniczenie może być użyte, aby zapewnić, że typ generyczny ma określoną właściwość lub metodę.
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
const stringLength = getLength("TypeScript");
const arrayLength = getLength([1, 2, 3]);
W tym przykładzie ograniczenie <T extends { length: number }>
zapewnia, że argument przekazany do getLength
ma właściwość length
.
Wiele generyków
TypeScript umożliwia używanie wielu typów generycznych w tej samej funkcji, klasie lub interfejsie. Jest to przydatne podczas pracy z parami wartości lub innymi strukturami danych obejmującymi wiele typów.
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const stringNumberPair = pair("TypeScript", 2024);
Ta funkcja, pair
, akceptuje dwa różne typy generyczne, T
i U
, i zwraca krotkę zawierającą oba typy.
Domyślne typy ogólne
Typy generyczne w TypeScript mogą również mieć typy domyślne. Jest to pomocne, gdy chcesz, aby typ generyczny miał typ zapasowy, jeśli nie podano konkretnego typu.
function identity<T = string>(value: T): T {
return value;
}
const defaultString = identity("Hello"); // T is string
const customNumber = identity<number>(100); // T is number
W tym przykładzie, jeśli do identity
nie zostanie przekazany żaden typ, domyślnie zostanie przyjęty typ string
.
Używanie typów generycznych z interfejsami
Generyki można stosować z interfejsami do definiowania złożonych struktur, w których typy nie są stałe. Dodaje to elastyczności do sposobu zarządzania danymi.
interface Container<T> {
value: T;
}
const stringContainer: Container<string> = { value: "Hello" };
const numberContainer: Container<number> = { value: 42 };
Interfejs Container
jest przeznaczony do przechowywania wartości dowolnego typu, co umożliwia tworzenie różnych rodzajów kontenerów o określonych typach.
Klasy generyczne
Klasy w TypeScript mogą być również generyczne. Jest to szczególnie przydatne podczas projektowania klas, które działają z różnymi typami danych, takimi jak klasy przechowywania danych lub kolekcji.
class DataStore<T> {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}
const stringStore = new DataStore<string>();
stringStore.add("Hello");
stringStore.add("TypeScript");
const numberStore = new DataStore<number>();
numberStore.add(42);
W tym przykładzie klasa DataStore
działa z dowolnym typem danych, zapewniając bezpieczny pod względem typu sposób przechowywania i pobierania elementów.
Wniosek
Zaawansowane generyki w TypeScript to potężne narzędzie do pisania elastycznego, wielokrotnego użytku i bezpiecznego pod względem typu kodu. Dzięki stosowaniu ograniczeń, wielu typów, wartości domyślnych i generyków w klasach i interfejsach programiści mogą pisać bardziej złożony i solidny kod. Zrozumienie i wykorzystanie tych zaawansowanych koncepcji zapewnia większą elastyczność i bezpieczeństwo typu w aplikacjach.