Reputation: 269
I want to get a union of all the keys under states
in this object type,
I have a nested object of state
keys. I want to get a union of all these keys under state
in dot notation.
For example, for this config:
type Config = {
initial: string;
states: {
idle: {
on: {
START: string;
};
};
running: {
on: {
PAUSE: string;
};
};
paused: {
initial: string;
states: {
frozen: {
on: {
HEAT: string;
};
};
};
on: {
RESET: string;
};
};
};
I want 'idle' | 'running' | 'paused' | 'paused.frozen'
Is this possible? Any ideas?
Upvotes: 3
Views: 759
Reputation: 15096
You can do this with a recursive conditional type like this:
type StateKeys<T> = T extends {states: infer S}
? keyof S | StateKeys<S[keyof S]>
: never
type Test = StateKeys<Config>
// type Test = "idle" | "running" | "paused" | "frozen"
Ah, I missed that you needed paused.frozen
instead of just frozen
. For what it's worth, my old solution could be fixed like this, using just conditional types:
type StateKeysForKey<S, K> = K extends keyof S & string
? `${K}.${StateKeys<S[K]>}`
: never
type StateKeys<T> = T extends {states: infer S}
? keyof S | StateKeysForKey<S, keyof S>
: never
type Test = StateKeys<Config>
// type Test = "idle" | "running" | "paused" | "paused.frozen"
Upvotes: 1
Reputation: 327614
Looks like another job for recursive conditional types as well as template literal types:
type StatesKeys<T> = T extends { states: infer S } ? {
[K in Extract<keyof S, string>]: K | `${K}.${StatesKeys<S[K]>}`
}[Extract<keyof S, string>] : never
type ConfigStatesKeys = StatesKeys<Config>;
// type ConfigStatesKeys = "idle" | "running" | "paused" | "paused.frozen"
StatesKeys<T>
inspects T
for its states
property S
, and generates for each of its keys K
the union we want, which is K
itself, plus the possible concatenation of K
with a dot and StatesKeys<S[K]>>
. That is, we are concatenating each key K
with any nested keys from S[K]
. If there are no nested keys, and StatesKeys<S[K]>
is never
, the template literal will also become never
, so we don't have to special-case it.
Upvotes: 6
Reputation: 3088
You can use keyof
keyword, in your particular example one solution could be keyof states
Upvotes: -2