web-dev-qa-db-fra.com

Types à partir des clés et des valeurs d'objet dans Typescript

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.

7
dx_over_dt

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"
11
artem

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.

IDE

0
setdvd