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?
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.
Playground link to code
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"
TypeScript playground
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"
TypeScript playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With