Reducing nested schema using TypeScript static typing

90 Views Asked by At

Recently I've stuck on complicated task, being almost a challenge. And to solve it, you only need to make a reducing of the original data using static typing (TypeScript).

Input

{
  schemaName: 'foo',
  def: Foo,
  struct: {
    field1: string,
    field2: {
      objectKey: number,
    },
    field3: {
      __ref: true,
      schema: {
        schemaName: 'bar',
        def: Bar,
        struct: {
          field4: number,
          field5: {
            __ref: true,
            schema: {
              schemaName: 'baz',
              def: Baz,
              struct: {
                field6: string,
              },
            },
          },
        },
      },
    },
    field7: {
      __ref: true,
      schema: {
        schemaName: 'qux',
        def: Qux,
        struct: {
          field8: boolean,
        }
      },
    },
  },
}

Output

And the task is to transform this structure into the following:

type SchemaReduced = {
  foo: Foo,
  bar: Bar,
  baz: Baz,
  qux: Qux,
};

My attempt

type FilterReferences<U> = U extends {__ref: true} ? U : never;
type ExtractNestedSchemas<S extends Schema<any, any, any>> = FilterReferences<S['struct'][keyof S['struct']]>['schema'];

type ReduceSchema<S extends Schema<any, any, any>> = {
  [name in S['schemaName']]: S['def']
} & {
  [name in ExtractNestedSchemas<S>['schemaName']]: ExtractNestedSchemas<S>['def']
} & {
  [name in ExtractNestedSchemas<ExtractNestedSchemas<S>>['schemaName']]: ExtractNestedSchemas<ExtractNestedSchemas<S>>['def']
};
type testReducer = {
    foo: Foo;
} & {
    bar: Bar | Qux;
    qux: Bar | Qux;
} & {}

In the attached playground, I tried to do at least something to solve it, but attempts were in vain. Main problems:

  • Nesting can be of any depth, but I never came up with recursive Reduce.
  • {baz: Baz} is missing. But if you drop field7, & {baz: Baz} should appear. This is a bug.
  • Instead of the desired {bar: Bar, qux: Qux} I'm getting {bar: Bar | Qux, qux: Bar | Qux}.

This is not someone else's challenge, the task is mine. How can I solve it?

TS Playground.

0

There are 0 best solutions below