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 dropfield7
,& {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?