Je veux pouvoir affecter une propriété d'objet à une valeur à partir d'une clé et d'une valeur en tant qu'entrées tout en étant capable de déterminer le type de la valeur. C'est un peu difficile à expliquer, donc ce code devrait révéler le problème:
type JWT = { id: string, token: string, expire: Date };
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) };
function print(key: keyof JWT) {
switch (key) {
case 'id':
case 'token':
console.log(obj[key].toUpperCase());
break;
case 'expire':
console.log(obj[key].toISOString());
break;
}
}
function onChange(key: keyof JWT, value: any) {
switch (key) {
case 'id':
case 'token':
obj[key] = value + ' (assigned)';
break;
case 'expire':
obj[key] = value;
break;
}
}
print('id');
print('expire');
onChange('id', 'def456');
onChange('expire', new Date(2018, 3, 14));
print('id');
print('expire');
onChange('expire', 1337); // should fail here at compile time
print('expire'); // actually fails here at run time
J'ai essayé de changer value: any
en value: valueof JWT
mais cela n'a pas fonctionné.
Idéalement, onChange('expire', 1337)
échouerait car 1337
n'est pas un type Date.
Comment puis-je changer value: any
pour être la valeur de la clé donnée?
UPDATE: Le titre de la question semble attirer les personnes à la recherche d'une union de tous les types de valeur de propriété possibles, de la même manière que keyof
vous donne l'union de tous les types de clé de propriété possibles. Aidons ces gens d'abord. Vous pouvez créer une ValueOf
analogue à keyof
, en utilisant types de recherche avec keyof T
comme clé, comme suit:
type ValueOf<T> = T[keyof T];
qui te donne
type Foo = { a: string, b: number };
type ValueOfFoo = ValueOf<Foo>; // string | number
Pour la question indiquée, vous pouvez utiliser des clés individuelles, plus étroites que keyof T
, pour extraire uniquement le type de valeur qui vous tient à cœur:
type sameAsString = Foo['a']; // lookup a in Foo
type sameAsNumber = Foo['b']; // lookup b in Foo
Pour vous assurer que la paire clé/valeur "correspond bien" dans une fonction, vous devez utiliser génériques ainsi que des types de recherche, comme celui-ci:
declare function onChange<K extends keyof JWT>(key: K, value: JWT[K]): void;
onChange('id', 'def456'); // okay
onChange('expire', new Date(2018, 3, 14)); // okay
onChange('expire', 1337); // error. 1337 not assignable to Date
L'idée est que le paramètre key
permet au compilateur d'inférer le paramètre générique K
. Ensuite, il faut que value
corresponde à JWT[K]
, le type de recherche dont vous avez besoin.
J'espère que ça t'as aidé; bonne chance!
Si quelqu'un cherche toujours l'implémentation de valueof
à quelque fin que ce soit, voici une version que j'ai proposée:
type valueof<T> = T[keyof T]
Usage:
type actions = {
a: {
type: 'Reset'
data: number
}
b: {
type: 'Apply'
data: string
}
}
type actionValues = valueof<actions>
Fonctionne comme prévu :) Retourne une union de tous les types possibles