J'ai deux ensembles de valeurs de chaîne que je souhaite mapper de l'un à l'autre en tant qu'objet constant. Je veux générer deux types à partir de ce mappage: un pour les clés et un pour les valeurs.
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
};
Les touches sont assez faciles:
type Keys = keyof typeof KeyToVal;
J'ai du mal à obtenir un type de compilation pour les valeurs. Je pensais que peut-être l'un d'entre eux fonctionnerait:
type Values = typeof KeyToVal[Keys];
type Values<K> = K extends Keys ? (typeof KeyToVal)[K] : never;
type Prefix<
K extends Keys = Keys,
U extends { [name: string]: K } = { [name: string]: K }
> = {[V in keyof U]: V}[K];
Tout cela fait que Values
est string
. J'ai également essayé d'adapter les deux réponses à Comment déduire des mapValues typées en utilisant des recherches en dactylographie? , mais soit j'ai mal mes adaptations, soit les réponses ne correspondaient pas à mon scénario en premier lieu.
Le compilateur élargira le type littéral de chaîne à string
, sauf si certaines conditions spécifiques sont remplies, comme expliqué dans github issues and PR , ou assertion const est utilisé pour la valeur littérale. Les assertions de const sont apparues dans TypeScript 3.4:
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
} as const;
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"
Avant la 3.4, il existait une solution de contournement pour obtenir le même effet. Pour que le compilateur infère des types littéraux, vous avez dû passer votre objet à travers une fonction avec des paramètres de type générique convenablement conçus, celui-ci semble faire l'affaire dans ce cas:
function t<V extends string, T extends {[key in string]: V}>(o: T): T {return o}
Le but de cette fonction est de capturer et de conserver les types pour permettre l'inférence de type, c'est totalement inutile sinon, mais avec cela vous pouvez avoir
const KeyToVal = t({
MyKey1: 'myValue1',
MyKey2: 'myValue2',
});
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"
Vous essayez de déduire le type de l'objet (qui peut avoir n'importe quel nombre de clés/valeurs). Vous pouvez essayer de décrire le type (ou peut-être mieux une interface) en premier, puis déduire Kyes et valeurs comme ceci:
type KeyToObjMap = {
some: "other",
more: "somemore",
};
type Keys = keyof KeyToObjMap;
type Values = KeyToObjMap[Keys];
let one: Values = "some";
let two: Values = "other";
let three: Keys = "some";
let four: Values = "somemore";
let five: Keys = "fun";
Et vous aurez un surlignage correct dans IDE.