简体   繁体   English

TypeScript 来自嵌套 object 的模板文字字符串

[英]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>检查Tstates属性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 ,因此我们不必对其进行特殊处理。

Playground link to code Playground 代码链接

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"

TypeScript playground TypeScript操场

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM