[英]TypeScript template literal string from nested object
I want to get a union of all the keys under states
in this object type,我想得到这个 object 类型中所有
states
下的键的联合,
I have a nested object of state
keys.我有一个嵌套的 object
state
键。 I want to get a union of all these keys under state
in dot notation.我想以点表示法获得
state
下所有这些键的联合。
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'
我想要
'idle' | 'running' | 'paused' | 'paused.frozen'
'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]>>
. StatesKeys<T>
检查T
的states
属性S
,并为它的每个键K
生成我们想要的联合,即K
本身,加上K
与点和StatesKeys<S[K]>>
的可能连接。 That is, we are concatenating each key K
with any nested keys from S[K]
.也就是说,我们将每个键
K
与来自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.如果没有嵌套键,且
StatesKeys<S[K]>
为never
,则模板文字也将变为never
,因此我们不必对其进行特殊处理。
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 TypeScript操场
Ah, I missed that you needed paused.frozen
instead of just frozen
.啊,我错过了您需要
paused.frozen
而不是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"
You can use keyof
keyword, in your particular example one solution could be keyof states
您可以使用
keyof
关键字,在您的特定示例中,一种解决方案可能是keyof states
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.