Menu

Omit w TypeScript: usuwanie właściwości z typu (przykłady)

Omit<T, K> tworzy typ ze wszystkimi właściwościami T poza kluczami K. Zobacz Omit z jednym i kilkoma kluczami, nadpisywanie typu właściwości, usuwanie właściwości w czasie działania, Omit a Exclude i Pick, dlaczego Omit przyjmuje nieistniejące klucze, ścisły Omit oraz Omit na uniach.

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

Omit<T, K> to wbudowany typ narzędziowy, który tworzy typ obiektowy ze wszystkimi właściwościami T poza kluczami wymienionymi w K. Klasyczne zastosowanie: typ User z polem password i jego publiczna wersja bez tego pola.

PublicUser pozostaje zsynchronizowany z User: dodaj pole do User, a pojawi się też w PublicUser, podczas gdy password zostaje poza nim. Omit działa tylko na typach; to destrukturyzacja w toPublic usuwa właściwość z rzeczywistego obiektu.

Pomijanie kilku kluczy

Drugi argument to unia, więc wymień przez | tyle kluczy, ile potrzebujesz:

"Typ bez pól generowanych przez serwer" to najczęstszy Omit w prawdziwym kodzie: jeden typ modelu, a Omit wyprowadza z niego kształt danych wejściowych dla formularzy tworzenia i żądań API.

Jak zdefiniowany jest Omit

Omit jest zbudowany z dwóch innych typów narzędziowych:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Czytaj od środka: keyof T to unia wszystkich kluczy, Exclude<keyof T, K> usuwa z niej niechciane klucze, a Pick zachowuje pozostałe. Tak więc Omit<User, "password"> to Pick<User, "id" | "name" | "email">. Ponieważ Pick mapuje po kluczach T, modyfikatory readonly i ? na pozostałych właściwościach zostają zachowane.

Zwróć uwagę na ograniczenie: K extends keyof any, a nie K extends keyof T. Ten szczegół jest tematem następnej sekcji.

Omit nie sprawdza, czy klucz istnieje

keyof any to string | number | symbol, więc Omit przyjmuje dowolny klucz, także taki, którego T nie ma. Literówka się kompiluje i niczego nie usuwa:

Nigdzie żadnego błędu, a hasło wychodzi w JSON-ie. Luźne ograniczenie wybrano celowo, gdy Omit dodano w TypeScript 3.5. Powody zespołu: w kodzie generycznym pomijane klucze często nie pochodzą z T (funkcja łącząca dwa obiekty może otypować swój argument rest jako Omit<T1, keyof T2>), Exclude też nie ogranicza swojego drugiego parametru, a wersja z ograniczeniem zepsułaby wiele ręcznie napisanych typów Omit, które projekty już miały. W codziennym kodzie ściślejsza wersja wyłapuje literówkę:

index.ts(10,36): error TS2344: Type '"pasword"' does not satisfy the constraint 'keyof User'.
index.ts(11,7): error TS2741: Property 'password' is missing in type '{ id: number; name: string; }' but required in type 'PublicUser'.

Liczy się pierwszy błąd: klucz jest sprawdzany względem keyof User. Drugi z niego wynika, bo nic nie zostało pominięte i PublicUser nadal wymaga password. Popraw pisownię na "password" i kod się skompiluje. Wiele projektów definiuje go raz we wspólnym pliku typów i używa zamiast Omit.

Nadpisywanie typu właściwości

Interfejs nie może rozszerzyć innego i zmienić właściwości na niezgodny typ: interface ApiUser extends User { id: string } kończy się error TS2430: Interface 'ApiUser' incorrectly extends interface 'User'. Najpierw pomiń właściwość, a potem zadeklaruj ją ponownie:

Z aliasem typu to samo robi przecięcie: type ApiUser = Omit<User, "id"> & { id: string }. Bez Omit przecięcie User & { id: string } dałoby id typ number & string, czyli never.

Omit na uniach

Omit nie jest rozdzielny. Na unii zaczyna od keyof całej unii, które zawiera tylko klucze wspólne dla wszystkich elementów, więc własne właściwości elementów znikają:

index.ts(8,39): error TS2353: Object literal may only specify known properties, and 'radius' does not exist in type 'NewShape'.

NewShape stał się { kind: "circle" | "square" }. Aby pominąć klucz w każdym elemencie osobno, zastosuj Omit wewnątrz rozdzielnego typu warunkowego:

T extends unknown ? ... : never jest zawsze prawdziwe; jest tam tylko po to, żeby typ warunkowy rozdzielił się na elementy unii. Strona o typach warunkowych wyjaśnia, dlaczego to działa. Używaj DistributiveOmit zawsze, gdy typ, z którego pomijasz, jest unią rozróżnialną.

Pomijanie zagnieżdżonej właściwości

Omit patrzy tylko na klucze najwyższego poziomu, więc Omit<Settings, "editor.wordWrap"> niczego nie usuwa (i, jak pokazano wyżej, nie protestuje). Aby usunąć właściwość poziom niżej, pomiń rodzica i dodaj go z powrotem z jego własnym Omit:

Settings["editor"] to indexed access type: nazywa zagnieżdżony typ obiektowy, żeby Omit mógł na nim działać.

Usuwanie właściwości w czasie działania

Omit zmienia tylko typ. Aby utworzyć obiekt bez tych właściwości, usuń je destrukturyzacją albo napisz małą funkcję generyczną, której typ zwracany to Omit:

Funkcja ogranicza K do keyof T, więc błędnie wpisany klucz to błąd w miejscu wywołania. Kopia jest płytka: zagnieżdżone obiekty są współdzielone z oryginałem.

Omit a Pick a Exclude

Działa naZachowujePrzykładWynik
Omit<T, K>typach obiektowychkażdą właściwość poza KOmit<User, "password">{ id; name; email }
Pick<T, K>typach obiektowychtylko właściwości z KPick<User, "id" | "name">{ id; name }
Exclude<U, M>uniachelementy unii nieprzypisywalne do MExclude<"a" | "b" | "c", "a">"b" | "c"

Wybieraj między Omit a Pick na podstawie tego, co ma się stać, gdy typ źródłowy się rozrośnie. Omit automatycznie obejmuje nowe właściwości, co pasuje do "wszystko poza sekretem". Pick nigdy ich nie obejmuje, co pasuje do "dokładnie te pola" i jest bezpieczniejsze dla wszystkiego, co opuszcza twój serwer. Pick sprawdza swoje klucze względem keyof T; Omit tego nie robi.

Najczęściej zadawane pytania

Co robi Omit w TypeScript?

Omit<T, K> buduje nowy typ obiektowy ze wszystkimi właściwościami T poza tymi, których klucze są w K. Omit<User, "password"> to User bez password. Zmienia tylko typ; niczego nie usuwa z obiektu w czasie działania.

Jak pominąć kilka właściwości w TypeScript?

Przekaż unię kluczy jako drugi argument: Omit<User, "password" | "createdAt" | "updatedAt">. Każdy klucz z unii zostaje usunięty.

Czym różni się Omit od Exclude?

Omit usuwa właściwości z typu obiektowego: Omit<{ a: 1; b: 2 }, "a"> to { b: 2 }. Exclude usuwa elementy z unii: Exclude<"a" | "b", "a"> to "b". Omit jest zaimplementowany przez Exclude: Pick<T, Exclude<keyof T, K>>.

Dlaczego Omit nie zgłasza błędu dla klucza, który nie istnieje?

Jego parametr kluczy jest ograniczony do keyof any (dowolny string, liczba lub symbol), a nie do keyof T, więc literówka taka jak Omit<User, "pasword"> się kompiluje i niczego nie usuwa. Zdefiniuj type StrictOmit<T, K extends keyof T> = Omit<T, K>, żeby dostać błąd dla nieznanych kluczy.

Jak usunąć właściwość z obiektu w czasie działania w TypeScript?

Użyj destrukturyzacji z elementem rest: const { password, ...rest } = user;. TypeScript nadaje rest typ obiektu bez password, ten sam kształt co Omit<User, "password">, a właściwości naprawdę nie ma w nowym obiekcie.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ