TypeScript-sjabloonletterreeks uit genest object
Ik wil een vereniging krijgen van alle sleutels onder states in dit objecttype,
Ik heb een genest object van state-sleutels. Ik wil een unie krijgen van al deze sleutels onder state in dotnotatie.
Bijvoorbeeld, voor deze configuratie:
type Config = {
initial: string;
states: {
idle: {
on: {
START: string;
};
};
running: {
on: {
PAUSE: string;
};
};
paused: {
initial: string;
states: {
frozen: {
on: {
HEAT: string;
};
};
};
on: {
RESET: string;
};
};
};
Ik wil 'idle' | 'running' | 'paused' | 'paused.frozen'
Is dit mogelijk? Ideeën?
Antwoord #1
Lijkt ook een klus voor recursieve conditionele types en 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> inspecteert T op zijn states eigenschap S, en genereert voor elk van zijn sleutels K de vereniging die we willen, namelijk K zelf, plus de mogelijke concatenatie van K met een punt en StatesKeys<S[K]>>. Dat wil zeggen, we concatenateren elke sleutel K met eventuele geneste sleutels van S[K]. Als er geen geneste sleutels zijn, en StatesKeys<S[K]> never is, zal de template literal ook never worden, dus hoeven we hier geen speciale gevallen voor te maken.
Speeltuinlink naar code
Antwoord #2
Je kunt dit doen met een recursief conditioneel type zoals dit:
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-speeltuin
Ah, ik had gemist dat je paused.frozen nodig had in plaats van alleen frozen. Voor wat het waard is, mijn oude oplossing kon op deze manier worden aangepast, met alleen voorwaardelijke 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-speeltuin
