Was Record<K, T>
bedeutet in Typescript?
Typescript 2.1 führte den Record
Typ ein und beschrieb ihn in einem Beispiel:
// 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>
siehe Typoskript 2.1
Und die erweiterte Typen Seite erwähnt Record
unter dem Mapped Typ Überschrift neben Readonly
, Partial
und Pick
in dem, was scheint seine Definition zu sein:
type Record<K extends string, T> = { [P in K]: T; }
Readonly, Partial und Pick sind homomorph, Record hingegen nicht. Ein Hinweis darauf, dass Record nicht homomorph ist, ist, dass kein Eingabetyp zum Kopieren von Eigenschaften erforderlich ist von:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Und das ist es. Außer den obigen Zitaten gibt es keine andere Erwähnung Record
auf typescriptlang.org .
Fragen
Kann jemand eine einfache Definition dessen geben, was
Record
ist?Ist es
Record<K,T>
nur eine Art zu sagen, dass "alle Eigenschaften dieses Objekts einen Typ habenT
"? Wahrscheinlich nicht alle Eigenschaften, daK
hat einen Zweck ...Verbietet das
K
Generikum zusätzliche Schlüssel für das Objekt, die dies nicht sind?K
, oder erlaubt es sie und zeigt nur an, dass ihre Eigenschaften nicht transformiert werdenT
?Mit dem gegebenen Beispiel:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Ist es genau das gleiche?:
type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
quelle
Antworten:
A
Record<K, T>
ist ein Objekttyp, dessen EigenschaftsschlüsselK
und dessen Eigenschaftswerte sindT
. Das heißt,keyof Record<K, T>
ist äquivalent zuK
undRecord<K, T>[K]
ist (im Grunde) äquivalent zuT
.Wie Sie bemerken,
K
hat es einen Zweck ... die Eigenschaftsschlüssel auf bestimmte Werte zu beschränken. Wenn Sie alle möglichen Schlüssel mit Zeichenfolgenwerten akzeptieren möchten, können Sie Folgendes tun.Record<string, T>
Die idiomatische Methode hierfür ist die Verwendung einer Indexsignatur wie{ [k: string]: T }
.Es "verbietet" zusätzliche Schlüssel nicht genau: Schließlich darf ein Wert im Allgemeinen Eigenschaften haben, die in seinem Typ nicht explizit erwähnt werden ... aber es würde nicht erkennen, dass solche Eigenschaften existieren:
und es würde sie als überschüssige Eigenschaften behandeln, die manchmal abgelehnt werden:
und manchmal akzeptiert:
Ja!
Hoffentlich hilft das. Viel Glück!
quelle
Record<string, V>
zu bedeuten,{[x: string]: V}
wenn Sie wollen; Ich habe das wahrscheinlich sogar selbst gemacht. Die Indexsignaturversion ist direkter: Sie sind vom gleichen Typ, aber der erstere ist ein Typalias eines zugeordneten Typs, der als Indexsignatur ausgewertet wird, während der letztere nur die Indexsignatur direkt ist. Wenn alles andere gleich ist, würde ich letzteres empfehlen. Ebenso würde ich nichtRecord<"a", string>
anstelle von verwenden,{a: string}
wenn es nicht einen anderen zwingenden kontextuellen Grund dafür gäbe.Record<string, V>
macht nur Sinn, wenn Sie bereits wissen, wie Indexsignaturen in TypeScript funktionieren. Beispiel gegebenx: Record<string, string>
,x.foo
wird offenbar sein ,string
bei der Kompilierung, aber in Wirklichkeit ist wahrscheinlich zu seinstring | undefined
. Dies ist eine Lücke in der Funktionsweise--strictNullChecks
(siehe # 13778 ). Ich würde eher Neulinge mit beschäftigen{[x: string]: V}
direkt , anstatt sie zu erwarten , dass die Kette aus folgtRecord<string, V>
bis{[P in string]: V}
zum Index Signaturverhalten.Mit einem Datensatz können Sie einen neuen Typ aus einer Union erstellen. Die Werte in der Union werden als Attribute des neuen Typs verwendet.
Angenommen, ich habe eine Union wie diese:
Jetzt möchte ich ein Objekt erstellen, das Informationen zu allen Katzen enthält. Ich kann einen neuen Typ erstellen, indem ich die Werte in der CatName Union als Schlüssel verwende.
Wenn ich diese CatList erfüllen möchte, muss ich ein Objekt wie das folgende erstellen:
Sie erhalten eine sehr starke Typensicherheit:
Beispiel für eine reale Reaktion.
Ich habe dies kürzlich verwendet, um eine Statuskomponente zu erstellen. Die Komponente würde eine Status-Requisite erhalten und dann ein Symbol rendern. Ich habe den Code hier zur Veranschaulichung ziemlich stark vereinfacht
Ich hatte eine Gewerkschaft wie diese:
Ich habe dies verwendet, um ein Objekt wie das folgende zu erstellen:
Ich könnte dann rendern, indem ich ein Element aus dem Objekt in Requisiten zerlege, wie folgt:
Wenn die Statusvereinigung später erweitert oder geändert wird, kann meine Statuskomponente nicht kompiliert werden, und es wird ein Fehler angezeigt, den ich sofort beheben kann. Dadurch kann ich der App zusätzliche Fehlerzustände hinzufügen.
Beachten Sie, dass die eigentliche App Dutzende von Fehlerzuständen aufwies, auf die an mehreren Stellen verwiesen wurde. Daher war diese Art der Sicherheit äußerst nützlich.
quelle
type Statuses
gehe davon aus, dass die meiste Zeit in von Ihnen NICHT definierten Schreibweisen lebt. Ansonsten kann ich so etwas wie eine Schnittstelle mit einer Aufzählung sehen, die besser passt, oder?Dictionary<enum, additional_metadata>
. Der Datensatztyp ist eine hervorragende Möglichkeit, dieses Enum + Metadatenmuster darzustellen.