The question
Having the following object:
const categories = {
foo1: {
bar1: "baz1"
},
foo2: {
bar2: "baz2"
}
} as const
How could I dynamically use baz1
and baz2
as the accepted values, as so:
type Item = {
categories: Array<'baz1' | 'baz2'>
}
What I've done
I've managed to put together the following utils:
type Join<K, P> = K extends string | number
? P extends string | number
? `${K}${'' extends P ? '' : '.'}${P}`
: never
: never
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]]
type Leaves<T, D extends number = 10> = [D] extends [never]
? never
: T extends object
? { [K in keyof T]-?: Join<K, Leaves<T[K], Prev[D]>> }[keyof T]
: ''
Which allow me to do the following:
type CategoryKeys = Leaves<typeof categories> // `foo1.bar1`, `foo2.bar2`
The problem
But the problem is that this won't work:
type CategoryValues = typeof categories[CategoryKeys] // ❌
// or
type CategoryValues = typeof categories['foo1.bar1'] // ❌
Because what would actually work, afaik, is:
type CategoryValues = typeof categories['foo1']['bar1'] // `baz1`
Thank you!
CodePudding user response:
If you want just a union of all existed values, you can check this:
const categories = {
foo1: {
bar1: "baz1"
},
foo2: {
bar2: "baz2"
}
} as const
type Primitives = string | number | symbol;
type Values<T> = T[keyof T]
type ValuesUnion<T, Cache = T> =
T extends Primitives ? T : Values<{
[P in keyof T]:
| Cache | T[P]
| ValuesUnion<T[P], Cache | T[P]>
}>
type Result = ValuesUnion<typeof categories>
CodePudding user response:
As @captain-yossarian-from-ukraine suggested, this playground has the answer.
In type Result
, I just had to replace 'foo2.bar2'
with AllKeys
and it works as needed.
Thank you!