typescriptgenericsindex-signature

Merging keys of two interfaces when passing to generic type


I have two interfaces as follows:

interface Foo {
  foo: string;
}

interface Bar {
  prop1: string;
  prop2: string;
}

My goal is to create a type that combines these two interface keys with underline between them, something like this:

type MergeKeys<A,B> = {
  [P in keyof A + '_' + P2 in keyof B]: string;
};

type Result = MergeKeys<Foo,Bar>;

So that the result would be:

   interface Result {
      foo_prop1: string;
      foo_prop2: string;
    }

Is this even possible?


Solution

  • Here's one way to do it:

    type MergeKeys<A, B> = { [P in
      `${Exclude<keyof A, symbol>}_${Exclude<keyof B, symbol>}`
      ]: string; };
    

    The main idea is to use template literal types to perform the desired string concatenation.

    The only wrinkle is that the compiler will reject the simpler `${keyof A}_${keyof B}`, because TypeScript supports symbol-valued keys which cannot be serialized to strings via template literals. In order to convince the compiler to serialize keyof A, we have to get rid of the possibility that any symbol-valued keys will be in there. That's where the Exclude<T, U> utility type comes in. The type Exclude<keyof A, symbol> will return the union of all the keys of A which are not symbols (so you'll get any string or number literal types but no symbols).


    Okay, let's test it:

    type Result = MergeKeys<Foo, Bar>;
    /* type Result = {
        foo_prop1: string;
        foo_prop2: string;
    } */
    

    Looks good!

    Playground link to code