Co Record<K, T>
oznacza w maszynie?
Typescript 2.1 wprowadził Record
typ, opisując go na przykładzie:
// For every properties K of type T, transform it to U function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
patrz Typescript 2.1
Oraz zaawansowane typy strona wymienia Record
pod odwzorowane Rodzaje tytule obok Readonly
, Partial
i Pick
, w co wydaje się być jego definicja:
type Record<K extends string, T> = { [P in K]: T; }
Tylko do odczytu, Częściowe i Pick są homomorficzne, podczas gdy Record nie. Jedną wskazówką, że Record nie jest homomorficzny, jest to, że nie przyjmuje typu wejściowego do kopiowania właściwości z:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
I to wszystko. Poza powyższymi cytatami nie ma innej wzmianki o Record
na typescriptlang.org .
pytania
Czy ktoś może podać prostą definicję tego, co
Record
jest?Czy jest to
Record<K,T>
tylko sposób na powiedzenie „wszystkie właściwości tego obiektu będą miały typT
”? Prawdopodobnie nie wszystkie właściwości, ponieważK
mają jakiś cel ...Czy
K
rodzaj ogólny zabrania dodatkowych kluczy w obiekcie, które nie sąK
, czy też zezwala na nie i po prostu wskazuje, że ich właściwości nie są przekształcaneT
?W podanym przykładzie:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Czy to dokładnie to samo co to ?:
type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
źródło
Odpowiedzi:
A
Record<K, T>
jest typem obiektu, którego klucze właściwości sąK
i których wartości właściwości sąT
. Oznacza to, żekeyof Record<K, T>
jest równoważneK
iRecord<K, T>[K]
jest (w zasadzie) równoważneT
.Jak zauważyłeś,
K
ma na celu ... ograniczenie kluczy właściwości do określonych wartości. Jeśli chcesz akceptować wszystkie możliwe klucze o wartościach łańcuchowych, możesz zrobić coś podobnegoRecord<string, T>
, ale idiomatycznym sposobem jest użycie podpisu indeksu, takiego jak{ [k: string]: T }
.Nie „zabrania” dodatkowych kluczy: w końcu wartość może mieć właściwości, które nie zostały wyraźnie wymienione w jej typie ... ale nie rozpoznałaby, że takie właściwości istnieją:
i traktowałby je jako właściwości nadmiarowe, które czasami są odrzucane:
i czasami akceptowane:
Tak!
Mam nadzieję, że to pomoże. Powodzenia!
źródło
Record<string, V>
na myśli,{[x: string]: V}
jeśli chcesz; Prawdopodobnie sam to zrobiłem. Wersja podpisu indeksu jest bardziej bezpośrednia: są tego samego typu, ale pierwsza jest aliasem typu odwzorowanego typu, którego wynikiem jest podpis indeksu, podczas gdy druga jest po prostu podpisem indeksu bezpośrednio. Ponieważ wszystko inne jest równe, polecam to drugie. Podobnie nie użyłbymRecord<"a", string>
zamiast,{a: string}
chyba że byłby jakiś inny ważny kontekst kontekstowy, aby to zrobić.Record<string, V>
ma sens tylko wtedy, gdy wiesz już, jak działają podpisy indeksów w TypeScript. Np. Podanex: Record<string, string>
,x.foo
najwyraźniej będziestring
w czasie kompilacji, ale w rzeczywistości prawdopodobnie tak będziestring | undefined
. To jest luka w tym, jak--strictNullChecks
działa (patrz # 13778 ). Wolałbym, aby nowicjusze zajmowali się{[x: string]: V}
bezpośrednio, zamiast oczekiwać, że będą śledzić łańcuch odRecord<string, V>
przejścia{[P in string]: V}
do zachowania podpisu indeksu.Rekord umożliwia utworzenie nowego typu z Unii. Wartości w Unii są używane jako atrybuty nowego typu.
Na przykład powiedz, że mam taką Unię:
Teraz chcę utworzyć obiekt, który zawiera informacje o wszystkich kotach, mogę utworzyć nowy typ, używając wartości w CatName Union jako kluczy.
Jeśli chcę spełnić wymagania tej CatList, muszę utworzyć taki obiekt:
Otrzymujesz bardzo silne bezpieczeństwo typu:
Przykład reakcji w świecie rzeczywistym.
Użyłem tego ostatnio do stworzenia komponentu Status. Komponent otrzyma właściwość stanu, a następnie wyrenderuje ikonę. Bardzo uprościłem kod w celach ilustracyjnych
Miałem taki związek:
Użyłem tego do stworzenia takiego obiektu:
Mogłem wtedy renderować, rozkładając element z obiektu na rekwizyty, na przykład:
Jeśli unia Statusy zostanie później rozszerzona lub zmieniona, wiem, że mój składnik Status nie będzie się skompilował i otrzymam błąd, który mogę natychmiast naprawić. Dzięki temu mogę dodać dodatkowe stany błędów do aplikacji.
Zauważ, że rzeczywista aplikacja miała dziesiątki stanów błędów, do których odwoływały się w wielu miejscach, więc tego typu bezpieczeństwo było niezwykle przydatne.
źródło
type Statuses
żyje w typach NIE zdefiniowanych przez Ciebie? W przeciwnym razie widzę coś w rodzaju interfejsu z wyliczeniem, które jest lepiej dopasowane, prawda?Dictionary<enum, additional_metadata>
. Typ rekordu to świetny sposób na reprezentowanie tego wzorca metadanych wyliczenia +.