Que signifie Record<K, T>
dans Typescript?
TypeScript 2.1 a introduit le type Record
, en le décrivant dans un exemple:
// 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>
voir TypeScript 2.1
Et la page Advanced Types mentionne Record
sous l'en-tête Types mappés à côté de Readonly
, Partial
et Pick
, dans ce qui semble être sa définition. :
type Record<K extends string, T> = { [P in K]: T; }
Readonly, Partial et Pick sont homomorphes alors que Record ne l’est pas. Un indice que Record n’est pas homomorphique est qu’il n’est pas nécessaire de saisir un type d’entrée pour copier les propriétés:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Et c'est tout. Outre les citations ci-dessus, il n'y a pas d'autre mention de Record
sur typescriptlang.org .
Quelqu'un peut-il donner une définition simple de ce que Record
est?
Est-ce que Record<K,T>
est simplement un moyen de dire "toutes les propriétés de cet objet auront le type T
"? Probablement pas toutes les propriétés , puisque K
a une certaine utilité ...
Le générique K
interdit-il des clés supplémentaires sur l'objet qui ne sont pas K
, ou les autorise-t-il et indique-t-il simplement que leurs propriétés ne sont pas transformées en T
?
Avec l'exemple donné:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Est-ce exactement la même chose ?:
type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
- Quelqu'un peut-il donner une définition simple de ce que
Record
est?
Un Record<K, T>
est un type d'objet dont les clés de propriété sont K
et dont les valeurs de propriété sont T
. Autrement dit, keyof Record<K, T>
est équivalent à K
, et Record<K, T>[K]
est (fondamentalement) équivalent à T
.
- Est-ce que
Record<K,T>
est simplement un moyen de dire "toutes les propriétés de cet objet auront le typeT
"? Probablement pas tous les objets, puisqueK
a une raison d'être ...
Comme vous le constatez, K
a pour but ... de limiter les clés de propriété à des valeurs particulières. Si vous voulez accepter toutes les clés possibles avec une valeur de chaîne, vous pouvez faire quelque chose comme Record<string, T>
, mais la façon idiomatique de le faire est d'utiliser un signature d'index comme { [k: string]: T }
.
- Le générique
K
interdit-il des clés supplémentaires sur l'objet qui ne sont pasK
, ou les autorise-t-il et indique-t-il simplement que leurs propriétés ne sont pas transformées enT
?
Cela n'interdit pas exactement les clés supplémentaires: après tout, une valeur est généralement autorisée à avoir des propriétés non mentionnées explicitement dans son type ... mais elle ne reconnaît pas que de telles propriétés existent:
declare const x: Record<"a", string>;
x.b; // error, Property 'b' does not exist on type 'Record<"a", string>'
et il les traiterait comme propriétés excessives qui sont parfois rejetées:
declare function acceptR(x: Record<"a", string>): void;
acceptR({a: "hey", b: "you"}); // error, Object literal may only specify known properties
et parfois accepté:
const y = {a: "hey", b: "you"};
acceptR(y); // okay
Avec l'exemple donné:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Est-ce exactement la même chose ?:
type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
Oui!
J'espère que ça t'as aidé. Bonne chance!
Un enregistrement vous permet de créer un nouveau type à partir d'une union. Les valeurs dans l'Union sont utilisées en tant qu'attributs du nouveau type.
Par exemple, disons que j'ai une Union comme celle-ci:
type CatNames = "miffy" | "boris" | "mordred";
Maintenant, je veux créer un objet contenant des informations sur tous les chats, je peux créer un nouveau type en utilisant les valeurs de l'union CatName comme clés.
type CatList = Record<CatNames, {age: number}>
Si je veux satisfaire cette CatList, je dois créer un objet comme celui-ci:
const cats:CatList = {
miffy: { age:99 },
boris: { age:16 },
mordred: { age:600 }
}
Vous obtenez une sécurité de type très forte:
Je l'ai utilisé récemment pour créer un composant Status. Le composant recevrait un accessoire d'état, puis rendrait une icône. J'ai beaucoup simplifié le code ici à des fins d'illustration
J'ai eu un syndicat comme celui-ci:
type Statuses = "failed" | "complete";
J'ai utilisé cela pour créer un objet comme celui-ci:
const icons: Record<
Statuses,
{ iconType: IconTypes; iconColor: IconColors }
> = {
failed: {
iconType: "warning",
iconColor: "red"
},
complete: {
iconType: "check",
iconColor: "green"
};
Je pourrais ensuite rendre le rendu en déstructurant un élément de l'objet en accessoires, comme ceci:
const Status = ({status}) => <Icon {...icons[status]} />
Si l'union des statuts est ultérieurement étendue ou modifiée, je sais que la compilation de mon composant Status échouera et j'obtiendrai une erreur que je pourrai immédiatement corriger. Cela me permet d'ajouter des états d'erreur supplémentaires à l'application.
Notez que l'application réelle comportait des dizaines d'états d'erreur référencés à plusieurs endroits. Ce type de sécurité était donc extrêmement utile.