Menu

Utility types w TypeScript: pełna lista z przykładami

Wszystkie wbudowane utility types TypeScript w jednym miejscu: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, Parameters, ReturnType, Awaited, typy dla stringów i inne, każdy z jednozdaniowym opisem i przykładem do uruchomienia.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Utility types to typy generyczne wbudowane w TypeScript, które zamieniają jeden typ w inny. Zamiast pisać drugi typ User ze wszystkimi polami opcjonalnymi, piszesz Partial<User>; zamiast kopiować trzy pola, Pick<User, "id" | "name">. Są globalne, więc nie trzeba ich importować.

Kiedy User się zmienia, wszystkie cztery typy pochodne zmieniają się razem z nim. Biblioteka standardowa TypeScript (lib.es5.d.ts) deklaruje 22 utility types. Sekcje poniżej wymieniają je wszystkie, pogrupowane według rodzaju typu, na którym działają, z linkiem do szczegółowej strony tam, gdzie taka istnieje.

Typy obiektowe: Partial, Required, Readonly, Pick, Omit, Record

Utility typeCo robiPrzykład
Partial<T>robi wszystkie właściwości opcjonalnymiPartial<User> dla danych aktualizacji
Required<T>robi wszystkie właściwości wymaganymi (usuwa ?)Required<Config> po zastosowaniu wartości domyślnych
Readonly<T>robi wszystkie właściwości readonlyReadonly<State>
Pick<T, K>zostawia tylko klucze KPick<User, "id" | "name">
Omit<T, K>usuwa klucze KOmit<User, "password">
Record<K, V>typ obiektowy z kluczami K i wartościami VRecord<"en" | "de", string>

Required<T> to przeciwieństwo Partial<T>; strona o Partial omawia oba, łącznie z jawnym undefined, które przepuszcza taki spread jak ten.

Typy unii: Exclude, Extract, NonNullable

Utility typeCo robiPrzykład
Exclude<U, M>usuwa z unii elementy przypisywalne do MExclude<"a" | "b" | "c", "a"> to "b" | "c"
Extract<U, M>zostawia w unii elementy przypisywalne do MExtract<string | number, number> to number
NonNullable<T>usuwa null i undefinedNonNullable<string | null> to string

Te trzy działają na uniach, nie na obiektach. To najważniejsza różnica względem Pick i Omit, które przyjmują typ obiektowy i listę jego kluczy.

Typy funkcji i klas: Parameters, ReturnType i inne

Utility typeCo robiPrzykład
ReturnType<F>typ zwracany przez typ funkcjiReturnType<typeof createStore>
Parameters<F>typy parametrów jako krotkaParameters<typeof fetchPage>[0]
ConstructorParameters<C>parametry konstruktora klasy jako krotkaConstructorParameters<typeof Point>
InstanceType<C>typ instancji tworzonej przez konstruktorInstanceType<typeof Point>
ThisParameterType<F>typ parametru this funkcjiThisParameterType<typeof greet>
OmitThisParameter<F>typ funkcji bez parametru thistyp greet.bind(obj)
ThisType<T>ustala typ this w metodach literału obiektuużywany z noImplicitThis w API typu builder
NoInfer<T>blokuje wnioskowanie parametru typu z tej pozycjifallback: NoInfer<C>

typeof createOrder jest potrzebne, bo te utility types przyjmują typ, a createOrder jest wartością. Z klasami jest tak samo: typeof Point to typ konstruktora, a samo Point użyte jako typ oznacza już typ instancji.

NoInfer decyduje, skąd typ generyczny bierze swój typ:

Bez NoInfer TypeScript wywnioskowałby C z obu argumentów i rozszerzył go do "red" | "green" | "blue", więc literówka w wartości zapasowej przeszłaby bez błędu.

Typy dla stringów: Uppercase, Lowercase, Capitalize, Uncapitalize

Utility typeCo robiPrzykład
Uppercase<S>zamienia typ literału stringa na wielkie literyUppercase<"get"> to "GET"
Lowercase<S>zamienia go na małe literyLowercase<"GET"> to "get"
Capitalize<S>zamienia pierwszy znak na wielką literęCapitalize<"name"> to "Name"
Uncapitalize<S>zamienia pierwszy znak na małą literęUncapitalize<"Name"> to "name"

Te cztery są wbudowane w kompilator, a nie napisane w TypeScript, i najbardziej przydają się w template literal types, na przykład `on${Capitalize<E>}` dla nazw handlerów zdarzeń.

Promise: Awaited

Utility typeCo robiPrzykład
Awaited<T>typ, który dostajesz z await, z rozpakowaniem zagnieżdżonych promiseAwaited<Promise<Promise<number>>> to number

Awaited<ReturnType<typeof fn>> to standardowy sposób, żeby nazwać typ wyniku funkcji async bez deklarowania go osobno.

Łączenie utility types

Utility types można zagnieżdżać. Kilka kombinacji pojawia się na tyle często, że warto znać je na pamięć:

Zagnieżdżony utility type czyta się od środka na zewnątrz: Readonly<Pick<Post, "id" | "title">> najpierw zostawia dwie właściwości, a potem robi je tylko do odczytu. Z tych samych części powstaje helper PartialBy, który robi opcjonalnymi tylko niektóre klucze; strona o Partial pokazuje go w całości.

Utility types nic nie robią w czasie działania programu

Każdy utility type znika podczas kompilacji. Wartość z typem Omit<User, "password"> może w czasie działania nadal zawierać hasło, jeśli obiekt, z którego pochodzi, je miał:

Typ ogranicza tylko to, co twój kod może odczytać. Żeby usunąć pole z danych, wyjmij je destrukturyzacją jak w ostatnich liniach, a żeby zablokować zmiany w czasie działania, użyj Object.freeze, nie Readonly. Wbudowane typy to jednolinijkowe mapped types i conditional types, więc tymi samymi narzędziami napiszesz własne.

Najczęściej zadawane pytania

Czym są utility types w TypeScript?

To typy generyczne dostarczane razem z TypeScript, które przekształcają inne typy: Partial<T> robi wszystkie właściwości opcjonalnymi, Pick<T, K> zostawia tylko część właściwości, ReturnType<F> wyciąga typ zwracany przez funkcję i tak dalej. Są zadeklarowane w bibliotece standardowej, więc używasz ich bez żadnego importu.

Czy utility types trzeba importować?

Nie. Partial, Omit, Record, ReturnType i pozostałe to typy globalne z wbudowanych plików bibliotecznych TypeScript. Pisz Partial<User> gdziekolwiek chcesz; nie potrzebujesz importu ani pakietu npm.

Jakie utility types są wbudowane w TypeScript?

22, wszystkie zadeklarowane w lib.es5.d.ts: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, Parameters, ConstructorParameters, ReturnType, InstanceType, ThisParameterType, OmitThisParameter, ThisType, NoInfer, Awaited, Uppercase, Lowercase, Capitalize i Uncapitalize.

Czy utility types zmieniają obiekty w czasie działania programu?

Nie. Opisują tylko typy i znikają z wynikowego JavaScriptu. Omit<User, "password"> nie usuwa właściwości password, a Readonly<T> niczego nie zamraża. Żeby zmienić prawdziwy obiekt, napisz kod: destrukturyzację z rest, Object.freeze i tak dalej.

Czy mogę pisać własne utility types?

Tak. Wbudowane to zwykły TypeScript: większość to jednolinijkowe mapped types albo conditional types w lib.es5.d.ts. type Nullable<T> = { [K in keyof T]: T[K] | null } to własny utility type napisany w ten sam sposób.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ