0

I have the following type:

type Config = {
  key: string,
  label?: string,
  value?: any,
}

I want to be able to parse through a deeply nested object of these "Config's". Something like this:

  feature1: {
    field1: {
      key: `field1`,
    },
    field2: {
      key: `field2`,
    },
  },

  feature2: {
    group1: {
      field: {
        key: `group1_field`,
      },
    },
    group2: {
      field: {
        key: `group2_field`,
      },
    },
  },

  feature3: {
    group1: {
      subgroup1: {
        field: {
          key: `group1_subgroup1_field`,
        },
      },
      subgroup2: {
        field: {
          key: `group1_subgroup2_field`,
        },
      },
    },
  },

The config's can appear at any depth in the object.

How would I go about writing up a Typescript Type to handle this structure?

I've been playing around with this code thus far:

type Config = {
  key: string,
  label?: string,
  value?: any,
}

type ConfigMapping = {
  [key: string]: Config
}

export type NestedConfig<T> = T extends Config ? Config : {
  [K in keyof T]:
  T[K] extends (infer U)[] ? NestedConfig<U>[] :
  NestedConfig<T[K]>;
}

This is not yet working the way I want. I'm a bit unclear how to create this nested Type.

4
  • Why not something like this? Commented Apr 20, 2022 at 17:11
  • But what about if the Config is deeply nested, 2 or more levels deep? Commented Apr 20, 2022 at 17:21
  • any type disables typescript btw Commented Apr 20, 2022 at 18:02
  • I know about any, but I was hoping to actually utilize my defined Type. The answer below allowed me to do it. Commented Apr 20, 2022 at 18:39

1 Answer 1

1

Since you only want to recursively have constraint for Config node type, We can do it with NConfig type alias -

Code Playground

type Config = {
  key: string,
  label?: string,
  value?: any,
}

type NConfig = Config | Config[] |  { [key: string]: NConfig } 


let x: NConfig = {
   feature1: {
    field1: {
      key: `field1`,
    },
    field2: {
      key: `field2`,
      label: 'hey'
    },
  },

  feature2: {
    group1: {
      field: [{
        key: `group1_field`,
      }],
    },
    group2: {
      field: {
        key: `group2_field`,
      },
    },
  },

  feature3: {
    group1: {
      subgroup1: {
        field: {
          key: `group1_subgroup1_field`,
        },
      },
      subgroup2: {
        field: {
          key: `group1_subgroup2_field`,
        },
      },
    },
  },
}

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. This did the trick. It's basically 99% of the solution I was hoping for and is working very well for my needs. What would be even better though is if I can force things so that you only allow a Config on the end of the object tree if you know what I mean? For example: feature1: { key: 'test', group1: { field: { key: 'field' } } } Adding a key under feature1 should not actually be allowed. The deeply nested object only allows Config's at the bottom of the nested structure.
I think even that case is covered by NConfig. Typescript has structural types meaning if two types are assignable to each other then they are interchangeable. I guess it is not working for key in feature is because if you think even { key: 'field' } is the same as Config type as other fields are partial ({ key: string, label?: string, value?: any }), If you name key something else it won't work You can check in the code playground why key field name is assignable to config and lol is not! Code Link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.