typescript - Hur skapar man en unionstyp från nästlade arrayer?
Jag har ett konstant objekt som detta
const rack = {
topShelf: {
colors: ["red", "green"],
},
middleShelf: {
colors: ["yellow", "blue"],
},
bottomShelf: {
colors: ["orange", "purple"],
},
}
Och jag vill skapa en unionstyp som:
type Color = "red" | "green" | "yellow" | "blue" | "orange" | "purple"
Rack-objektet är bara ett exempel. I en verklig applikation har objektet omkring 30 fält.
Jag vet hur man gör det manuellt
type Color =
| typeof rack["topShelf"]["colors"][number]
| typeof rack["middleShelf"]["colors"][number]
| typeof rack["bottomShelf"]["colors"][number]
Men det är felbenäget och jag är säker på att det finns ett sätt att få denna unionstyp att härledas av Typescript.
Svar #1
Ja, det är möjligt.
const rack = {
topShelf: {
colors: ["red", "green"],
},
middleShelf: {
colors: ["yellow", "blue"],
},
bottomShelf: {
colors: ["orange", "purple"],
},
extraDeepNestedProperty: {
nestedProperty: {
colors: ['rgb']
}
}
} as const
type Rack = typeof rack
type IsNever<T> = [T] extends [never] ? true : false
type Union<T, Cache extends string = never> =
IsNever<keyof T> extends true
? Cache
: {
[Prop in keyof T]:
T[Prop] extends ReadonlyArray<string>
? Cache | T[Prop][number]
: Union<T[Prop], Cache>
}[keyof T]
type Result = Union<Rack>
Behandla Cache som en memoization.
Union är en rekursiv typ.
Lekplats Jag gjorde en generisk lösning som fungerar inte bara med 2 nivåer av nästling,
Svar #2
Jag har slutat upp med denna lösning:
const rack = {
topShelf: {
colors: ["red", "green"],
},
middleShelf: {
colors: ["yellow", "blue"],
},
bottomShelf: {
colors: ["orange", "purple"],
},
} as const
const colors = Object.values(rack).map(shelf => shelf.colors).flat()
type Color = typeof colors[number]
Jag kommer att behöva "colors" som ett värde vid körning senare, så i mitt specifika fall är denna lösning den bästa.
Men lösningen från @captain-yossarian är generell så jag markerade den som ett svar.
