2017-08-25 6 views
1

Donc, il y a une astuce que je trouve dans les typescript pour transformer un type d'objet en une union discriminée en mappant le type en paire clé-valeur puis en créant un type qui peut être n'importe quelle valeur dans la carte en utilisant le type keyof. Voici un exemple simple:Raison de [typof T] dans les génériques ayant une sémantique différente d'un type codé en dur?

type SourceType = 
{ 
    foo: number, 
    bar: string 
}; 
type MapWithKey<T> = {[P in keyof T]: { key: P, value: T[P] }} 
type DescriminatedUnion = MapWithKey<SourceType>[keyof SourceType]; 
//The DescriminatedUnion now has the following type 
DescriminatedUnion ≡ {key:"foo",value:string} | {key:"bar",value:number} 

Ceci est très utile si vous souhaitez spécifier une union discriminée très grand mais quand vous essayez de faire de cette construction vous complètement générique retrouvez avec un autre type.

type MakeDescriminatedUnion<T> = MapWithKey<T>[keyof T]; 
type DescriminatedUnion = MakeDescriminatedUnion<SourceType> 
//The DescriminatedUnion now has the followin type 
DescriminatedUnion ≡ {key:"foo"|"bar",value:number|string} 

Ceci devrait être du même type mais, pour une raison quelconque, il ne l'est pas. J'ai essayé de parcourir la documentation dactylographiée pour trouver un raisonnement pour ce comportement mais je ne peux pas. Est-ce que quelqu'un sait le raisonnement derrière cette différence? Ou mieux encore quelqu'un sait-il un moyen de contourner ce comportement et de le rendre totalement générique?

+3

[Cette question] (https://stackoverflow.com/questions/43898999/creating-a-discriminated-union-using-the-property-names-of-another-type) est très similaire, voici [github problème] (https://github.com/Microsoft/TypeScript/issues/15756), et [voici le correctif] (https://github.com/Microsoft/TypeScript/pull/18042) – artem

+0

Merci! C'est beaucoup plus que ce à quoi je m'attendais. @artem –

Répondre

1

Oui, this issue a mordu me et quite quelques others. Il est incroyable que, comme le mentionne @artem, a fix prévu pour TypeScript 2.6 a été introduit aujourd'hui!

Pendant ce temps, pour ceux d'entre nous coincé dans tapuscrit 2.4 terre, il existe une solution à l'aide default generic type parameters:

type MakeDiscriminatedUnion<T, M extends MapWithKey<T> = MapWithKey<T>> = M[keyof T]; 
type DiscriminatedUnion = MakeDiscriminatedUnion<SourceType> // okay now 

La valeur réelle de M ne soit pas évalué jusqu'à ce que vous utilisez MakeDiscriminatedUnion<SourceType>, de sorte que le compilateur a aucune chance de "simplifier" M[keyof T] comme il le fait ci-dessus.

Quoi qu'il en soit, c'est votre choix si vous utilisez la solution de contournement ou attendez que TypeScript 2.6. J'espère que cela pourra aider. Bonne chance!

+0

Merci pour le travail! Impossible de le trouver ailleurs fonctionne parfaitement! –