Уменьшение вложенной схемы с помощью статической типизации TypeScript

В последнее время я застрял на сложной задаче, это почти вызов. И чтобы решить эту проблему, вам нужно только уменьшить исходные данные с помощью статической типизации (TypeScript).

Вход

{
  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,
        }
      },
    },
  },
}

Вывод

И задача состоит в том, чтобы преобразовать эту структуру в такую:

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

Моя попытка

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;
} & {}

В пристроенной детской площадке пытался хоть что-то решить, но попытки оказались тщетными. Основные проблемы:

  • Вложенность может быть любой глубины, но я никогда не придумал рекурсивное сокращение.
  • {baz: Baz} отсутствует. Но если уронить field7, должно появиться & {baz: Baz}. Это ошибка.
  • Вместо желаемого {bar: Bar, qux: Qux} получаю {bar: Bar | Qux, qux: Bar | Qux}.

Это не чужая задача, это моя задача. Как я могу это решить?

TS площадка.


person avdotion    schedule 18.12.2020    source источник
comment
Это задача или вызов? ))))))   -  person captain-yossarian    schedule 19.12.2020
comment
@ captain-yossarian, я надеюсь, что если назвать задачу вызовом, она будет решена как можно скорее.   -  person avdotion    schedule 19.12.2020