Je voudrais stocker un mappage de chaîne -> chaîne dans un objet Typescript, et imposer que toutes les clés mappent sur des chaînes. Par exemple:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
Existe-t-il un moyen pour moi d'imposer que les valeurs doivent être des chaînes (ou tout autre type ..)?
typescript
Armentage
la source
la source
number
est également autorisé comme type d'indexationtype Keys = 'Acceptable' | 'String' | 'Keys'
type d'indexation (clé)?Ici, l'interface
AgeMap
applique les clés sous forme de chaînes et les valeurs sous forme de nombres. Le mot-cléname
peut être n'importe quel identifiant et doit être utilisé pour suggérer la syntaxe de votre interface / type.Vous pouvez utiliser une syntaxe similaire pour imposer qu'un objet possède une clé pour chaque entrée d'un type d'union:
Vous pouvez bien sûr en faire également un type générique!
Mise à jour du 10.10.2018: Découvrez la réponse de @ dracstaxi ci-dessous - il y a maintenant un type intégré
Record
qui fait la plupart de cela pour vous.Mise à jour 1.2.2020: j'ai entièrement supprimé les interfaces de mappage prédéfinies de ma réponse. La réponse de @ dracstaxi les rend totalement hors de propos. Si vous souhaitez toujours les utiliser, consultez l'historique des modifications.
la source
x = {}; x[1] = 2;
dans Chrome puisObject.keys(x)
renvoie ["1"] etJSON.stringify(x)
renvoie '{"1": 2}'. Les cas d'angle avec typeofNumber
(par exemple Infinity, NaN, 1e300, 999999999999999999999 etc.) sont convertis en clés de chaîne. Méfiez - vous également d'autres cas de coin pour les clés de chaîne commex[''] = 'empty string';
,x['000'] = 'threezeros';
x[undefined] = 'foo'
.Une mise à jour rapide: depuis Typescript 2.1, il existe un type intégré
Record<T, K>
qui agit comme un dictionnaire.Un exemple de documents:
Documentation TypeScript 2.1 sur
Record<T, K>
Le seul inconvénient que je vois à utiliser ceci
{[key: T]: K}
est que vous pouvez encoder des informations utiles sur le type de clé que vous utilisez à la place de "clé"{[prime: number]: yourType}
.Voici une expression régulière que j'ai écrite pour aider à ces conversions. Cela ne convertira que les cas où l'étiquette est "clé". Pour convertir d'autres étiquettes, changez simplement le premier groupe de capture:
Trouver:
\{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}
Remplacer:
Record<$2, $3>
la source
{}
?Record
s (contrairement à, disons, JavascriptMap
) ne fournissent qu'un moyen d'appliquer le contenu d'un objet littéral. Vous ne pouvez pasnew Record...
etconst blah: Record<string, string>;
allez compilerconst blah;
.Record
:const isBroken: Record<"hat" | "teapot" | "cup", boolean> = { hat: false, cup: false, teapot: true };
La réponse de @Ryan Cavanaugh est totalement correcte et toujours valable. Il vaut toujours la peine d'ajouter qu'à partir de l'automne 2016, lorsque nous pouvons affirmer que ES6 est pris en charge par la majorité des plates-formes, il est presque toujours préférable de s'en tenir à Map chaque fois que vous avez besoin d'associer certaines données à une clé.
Quand on écrit
let a: { [s: string]: string; }
nous devons nous rappeler qu'après la compilation du typage, il n'y a pas de données de type, elles ne sont utilisées que pour la compilation. Et {[s: chaîne]: chaîne; } sera compilé en {} seulement.Cela dit, même si vous écrivez quelque chose comme:
Cela ne compilera tout simplement pas (même pour
target es6
, vous obtiendrezerror TS1023: An index signature parameter type must be 'string' or 'number'.
Donc, pratiquement, vous êtes limité avec une chaîne ou un nombre comme clé potentielle, il n'y a donc pas beaucoup de sens à appliquer la vérification de type ici, surtout en gardant à l'esprit que lorsque js essaie d'accéder à la clé par numéro, il la convertit en chaîne.
Il est donc tout à fait sûr de supposer que la meilleure pratique consiste à utiliser Map même si les clés sont des chaînes, alors je m'en tiendrai à:
la source
let dict: {[key in TrickyKey]: string} = {}
- oùTrickyKey
est un type littéral de chaîne (par exemple"Foo" | "Bar"
).Map
objets natifs . Les cartes sont livrées avec une surcharge de mémoire supplémentaire et (plus important encore) doivent être instanciées manuellement à partir de toutes les données stockées sous forme de chaîne JSON. Ils sont souvent très utiles, mais pas uniquement pour en retirer des types.Définir l'interface
Appliquer la clé comme clé spécifique de l'interface des paramètres
la source
En s'appuyant sur la réponse de @ shabunc, cela permettrait d'appliquer la clé ou la valeur - ou les deux - à tout ce que vous souhaitez appliquer.
Devrait également fonctionner en utilisant
enum
au lieu d'unetype
définition.la source