TS : Composition par énumérations
Dans une simple variante de saisie via enum, notre type ressemble à ceci :
export enum TypeFields{
id = 'id',
title = 'title'
...
}
//type Record<K extends string, T> = { [P in K]: T }
export type Type = Record<TypeFields,string>
// converted to:
//
// type Type = {
// id: string;
// title: string;
// }
L'avantage de cette approche est que l'on crée des types sur la base de listes de champs déjà décrites, limitant ainsi le champ d'erreurs possibles. Dans cette veine, les énumérations deviennent une abstraction supplémentaire qui vous permet de penser non pas en types, mais en un sous-ensemble de champs.
Cependant, la nuance d'une telle composition est que nous n'avons pas d'outil pour composer plusieurs énumérations en un seul type commun.
L'idée est de concevoir un type utilitaire qui nous permettra de fusionner des paires [enum,type][] en un seul type dans lequel chaque champ aura le type attribué à l'énumération et non à un seul champ.
Pour créer un tel type d'utilitaire, vous devez comprendre 2 principes importants :
Le principe de construction d'un type d'utilitaire récursif.
Le principe de l'enregistrement intermédiaire du résultat dans les types d'utilitaires.
Commençons à construire notre type avec une forme d'interaction avec lui :
Comme nous l'avons défini précédemment, nous voulons pouvoir fusionner plusieurs énumérations et donner à chacun d'eux un type
enum A {
a = 'a'
}
enum B {
b = 'b'
}
enum C {
c = 'c'
}
type MergedType = MergeEnums<[
[A,string],
[B,boolean],
[C,number],
]>
// expected result of MergeEnums utility type:
//
// type MergedType{
// [A.a]: string,
// [B.b]: boolean,
// [C.c]: number,
// }
export type MergeEnums<Entries extends [keyof any,unknown][]>
L'algorithme sera le suivant - nous prenons notre tableau d'entrées, le divisons en deux entités - la première paire et toutes les autres paires, après quoi nous transformons la première paire [Enum, T] en Record<Enum,T> et écrivons ceci tapez à l'accumulateur, répétez l'algorithme tant qu'il y a des paires sur la liste.
Voici un exemple d'implémentation :
type MergeEnums<
Entries extends [keyof any,unknown][], // enries array to process
Acc extends object = {} // accumulator
> =
Entries extends [infer CurrentEntry, ...infer ShiftedEntries] // shift first pair from entries array
? ShiftedEntries extends [keyof any, unknown][] // type compare check
? CurrentEntry extends [infer Enum,infer Type] // get enum and type for it from shifted entries pair
? Enum extends keyof any // type compare check
? MergeEnums<ShiftedEntries, Acc & Record<Enum, Type>> // new iteration of MergeEnums with updated accumulator
// recursion exit
: Acc
: Acc
: Acc
: Acc
enum A {
a = 'a'
}
enum B {
b = 'b'
}
enum C {
c = 'c'
}
type Test = MergeEnums<[
[A,string],
[B,boolean],
[C,number]
]>
const test: Test = {
[A.a]: 'true',
[B.b]: false,
[C.c]: 1
}
Pourquoi est-ce utile ?
L'avantage d'un tel utilitaire de type est que nous pouvons diviser le type résultant en blocs logiques de champs via une couche d'énumérations
enum UserProfileSomeRequiredFields{
id = 'id',
...
}
enum UserProfileSomeOptionalFields{
status = 'status',
lang = 'lang',
...
}
enum UserProfileSomeResources {
somePageResource = 'somePageResource',
someOtherResource = 'someOtherResource'
...
}
type SomeResponse = MergeEnums<[
[UserProfileSomeRequiredFields,number],
[UserProfileSomeOptionalFields,string],
[UserProfileSomeResources,boolean]
]>
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































