Appliquer le type des membres indexés d’un object Typescript?

Je voudrais stocker un mappage de chaîne -> chaîne dans un object Typescript et faire en sorte que toutes les clés soient associées à des chaînes. Par exemple:

var stuff = {}; stuff["a"] = "foo"; // okay stuff["b"] = "bar"; // okay stuff["c"] = false; // ERROR! bool != ssortingng 

Y a-t-il un moyen pour moi d’imposer que les valeurs doivent être des chaînes (ou n’importe quel type ..)?

 var stuff: { [s: ssortingng]: ssortingng; } = {}; stuff['a'] = ''; // ok stuff['a'] = 4; // error // ... or, if you're using this a lot and don't want to type so much ... interface SsortingngMap { [s: ssortingng]: ssortingng; } var stuff2: SsortingngMap = { }; // same as above 

Je porte ce fichier avec moi partout où je vais

 export interface ISsortingngTMap { [key: ssortingng]: T; }; export interface INumberTMap { [key: number]: T; }; export interface ISsortingngAnyMap extends ISsortingngTMap {}; export interface INumberAnyMap extends INumberTMap {}; export interface ISsortingngSsortingngMap extends ISsortingngTMap {}; export interface INumberSsortingngMap extends INumberTMap {}; export interface ISsortingngNumberMap extends ISsortingngTMap {}; export interface INumberNumberMap extends INumberTMap {}; export interface ISsortingngBooleanMap extends ISsortingngTMap {}; export interface INumberBooleanMap extends INumberTMap {}; 

ISsortingngTMap et INumberTMap sont des génériques et peuvent être utilisés pour créer des cartes de tout type (via let myTypeMap: ISsortingngTMap = {} ). Les autres sont des correspondances prédéfinies utiles entre les types littéraux courants.

La syntaxe importante ici est { [key: ssortingng]: T; } { [key: ssortingng]: T; } qui indique que l’interface applique un littéral d’object avec des clés de type ssortingng (la key mot peut être n’importe quel identifiant, et doit être utilisée pour indiquer l’importance de la clé) et des valeurs de type T Si vous vouliez construire un object avec la ssortingng “names” pour les clés et les valeurs boolean (et ne pas utiliser l’inheritance ci-dessus), son interface serait { [name: ssortingng]: boolean } .

La réponse de @Ryan Cavanaugh est tout à fait correcte et toujours valide. Cela vaut quand même la peine d’append qu’à partir de l’automne 16, nous pouvons affirmer que l’ES6 est supporté par la majorité des plates-formes.

Quand on écrit let a: { [s: ssortingng]: ssortingng; } let a: { [s: ssortingng]: ssortingng; } Nous devons nous rappeler que, après la compilation de typescript, il n’existe pas de données de type, mais uniquement pour la compilation. Et {[s: ssortingng]: ssortingng; } comstackra juste pour {}.

Cela dit, même si vous écrivez quelque chose comme:

 class TrickyKey {} let dict: {[key:TrickyKey]: ssortingng} = {} 

Cela ne comstack pas (même pour la target es6 , vous obtiendrez l’ error TS1023: An index signature parameter type must be 'ssortingng' or 'number'.

Donc, en pratique, vous êtes limité par une chaîne ou un nombre en tant que clé potentielle, vous n’avez donc pas vraiment besoin de vérifier le type, surtout en gardant à l’esprit que js tente d’accéder à la clé par numéro.

Il est donc tout à fait raisonnable de supposer que la meilleure pratique consiste à utiliser Map même si les clés sont des chaînes, donc je restrai fidèle à:

 let staff: Map = new Map(); 

S’appuyant sur la réponse de @ shabunc, cela permettrait d’appliquer soit la clé, soit la valeur – ou les deux – à tout ce que vous souhaitez appliquer.

 type IdentifierKeys = 'my.valid.key.1' | 'my.valid.key.2'; type IdentifierValues = 'my.valid.value.1' | 'my.valid.value.2'; let stuff = new Map(); 

Devrait également fonctionner en enum au lieu d’une définition de type .

Une mise à jour rapide: depuis Typescript 2.1, il existe un type intégré Record qui agit comme un dictionnaire.

Un exemple de docs:

 // For every properties K of type T, transform it to U function mapObject(obj: Record, f: (x: T) => U): Record const names = { foo: "hello", bar: "world", baz: "bye" }; const lengths = mapObject(names, s => s.length); // { foo: number, bar: number, baz: number } 

Documentation TypeScript 2.1 sur l’ Record

Le seul inconvénient que je trouve à utiliser avec cette {[key: T]:K est que vous pouvez encoder des informations utiles sur le type de clé que vous utilisez à la place de “key”, par exemple si votre object ne contient que des clés cela plaît tellement: {[prime: number]: yourType} .

Voici un regex que j’ai écrit pour vous aider avec 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:

Rechercher: \{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}

Remplacer: Record<$2, $3>