Home > Blockchain >  Extract paths to nested fields for properties that are optional in TypeScript
Extract paths to nested fields for properties that are optional in TypeScript

Time:02-05

I have a use case where I need to extract all possible paths to nested fields inside a TypeScript interface.

When I define a property within the "main" type that has nested and optional properties, then it works as expected. However, I am running into an issue with an optional property that points to another interface.

type NestedKeyOf<T extends object> = {
  [Key in keyof T & (string | number)]: T[Key] extends object
    ? `${Key}` | `${Key}.${NestedKeyOf<T[Key]>}`
    : `${Key}`;
}[keyof T & (string | number)];

interface MyParameters {
  Foo: string;
  Bar?: string;
}

interface MyObject {
  Parameters?: MyParameters;
  Foo: {
    Bar?: string;
  }
}

// Here, I'd expect "Parameters.Foo" and "Parameters.Bar" to also exist
// Instead, all I get is "Parameters" | "Foo" | "Foo.Bar"

type Path = NestedKeyOf<MyObject> // "Parameters" | "Foo" | "Foo.Bar"

Could someone please explain what is the reason for this behavior? Thanks!

CodePudding user response:

The problem is that type Test = MyObject["Parameters"] extends object ? true : false evaluates to false if Parameters is optional. You can fix it by excluding the case of it being undefined with Exclude<T[Key], undefined> extends object instead of T[Key] extends object (playground):

type NestedKeyOf<T extends object> = {
  [Key in keyof T & (string | number)]: Exclude<T[Key], undefined> extends object
    ? `${Key}` | `${Key}.${NestedKeyOf<Exclude<T[Key], undefined>>}`
    : `${Key}`;
}[keyof T & (string | number)];

interface MyParameters {
  Foo: string;
  Bar?: string;
}

interface MyObject {
  Parameters?: MyParameters;
  Foo: {
    Bar?: string;
  }
}

type Path = NestedKeyOf<MyObject>
  • Related