Home > Back-end >  Typescript generics: readonly values from interface children
Typescript generics: readonly values from interface children

Time:09-27

Given this input:

export type Test = {
    one: {
        a: string;
        b: string;
        c: string;
    };
    two: {
        a: string;
        b: string;
        d: string;
    };
}

I need a generics like CombinedChildren<T> which outputs the following type:

export type Combined = {
    a?: string;
    b?: string;
    c?: string;
    d?: string;
}

Basically, it takes the children properties and combines them, including them even if they're not present in all children.

Tried

export type KeyOfTest = Partial<Test[keyof Test]>
export type MappedKeyOfTest = Partial<{
    [key in keyof Test[keyof Test]]: Test[keyof Test][key]
}>

But none output exactly what want.

CodePudding user response:

We can break this down into a few steps. First, we get a union of all the child types by Test[keyof Test]. Then we want a union of all this type, so we use a utility type that converts union types to intersection types (taken from this answer by @jcalz). Finally, we apply Partial to the resulting type.

export type Test = {
    one: {
        a: string;
        b: string;
        c: string;
    };
    two: {
        a: string;
        b: string;
        d: string;
    };
    three: {
      a: string;
      e: number;
    }
}

// union to intersection converter by @jcalz: https://stackoverflow.com/a/50375286/8580499
// Intersect<{ a: 1 } | { b: 2 }> = { a: 1 } & { b: 2 }
type Intersect<T> = (T extends any ? ((x: T) => 0) : never) extends ((x: infer R) => 0) ? R : never;

// Combined = { a?: string; b?: string; c?: string; d?: string; e?: number }
type Combined = Partial<Intersect<Test[keyof Test]>>;

Playground link

CodePudding user response:

How about using union operator:

export type Combined = Test['one'] & Test['two'];

OR

export type Combined = Partial<Test['one'] & Test['two']>;
  • Related