Je définis un AbstractModel
comme ceci:
export interface AbstractModel {
[key: string]: any
}
Ensuite, je déclare le type Keys
:
export type Keys = keyof AbstractModel;
Je m'attendrais à ce que tout ce qui a le type Keys soit interprété de manière univoque comme une chaîne, par exemple:
const test: Keys;
test.toLowercase(); // Error: Property 'toLowerCase' does not exist on type 'string | number'. Property 'toLowerCase' does not exist on type 'number'.
Est-ce un bogue de TypeScript (2.9.2), ou ai-je raté quelque chose?
Comme défini dans les notes de publication de TypeScript 2.9, si vous saisissez une interface avec une signature d'index de chaîne, elle retourne une union de chaîne et de nombre
Étant donné un type d'objet X, la clé de X est résolue comme suit:
Si X contient une signature d'index de chaîne, keyof X est une union de chaîne, de nombre et de types littéraux représentant des propriétés de type symbole, sinon
Si X contient une signature d'index numérique, keyof X est une union de nombre et les types littéraux représentant des propriétés de type chaîne et de type symbole, sinon
keyof X est une union des types littéraux représentant des propriétés de type chaîne, de type nombre et de symbole.
En effet: JavaScript convertit les nombres en chaînes lors de l'indexation d'un objet:
[..] lors de l'indexation avec un nombre, JavaScript le convertit en fait en chaîne avant l'indexation en objet. Cela signifie que l'indexation avec 100 (un nombre) est la même chose que l'indexation avec "100" (une chaîne), donc les deux doivent être cohérents.
Exemple:
let abc: AbstractModel = {
1: "one",
};
console.log(abc[1] === abc["1"]); // true
Lorsque vous ne voulez que les clés de chaîne, vous ne pouvez extraire les clés de chaîne de votre interface que comme suit:
type StringKeys = Extract<keyof AbstractModel, string>;
const test: StringKeys;
test.toLowerCase(); // no error
Le compilateur TypeScript fournit également une option pour obtenir le comportement antérieur à 2.9 de keyof
:
keyofStringsOnly (booléen) par défaut
false
Résolvez
keyof
en chaîne uniquement pour les noms de propriétés à valeur (pas de chiffres ni de symboles).
J'ai rencontré un problème similaire. Je l'ai résolu en appliquant la clé à une chaîne:
export type Keys = keyof AbstractModel & string;
Une autre option serait de convertir la clé en chaîne: test.toString().toLowercase()