Search code examples
typescripttypescript-genericstyping

Type definition for overlapping types


I would like to create the type definition for a function that takes two objects of different type but with common set of keys:

function myFunc(left, right, keys) {
  // simplified:
  for (const key of keys) {
    console.log(key, left[key] === right[key])
  }

  return { left, right }
}

const left = {a: 1, b: 2}
const right = {b: 2, c: 3}
myFunc(left, right, ["b"])

This approach works, but changes the type of the returned right which bites me in the code after the function call:

function myFunc<
  Left,
  Keys extends keyof Left
>(
  left: Left,
  right: Pick<Left, Keys>,
  keys: Keys[],
): {
  left: Left
  right: Pick<Left, Keys>
} {
  // ...
}

I want the returned type to be the same:

function myFunc<
  Left,
  Right extends Pick<Left, Keys>,
  Keys extends keyof Left & keyof Right
>(
  left: Left,
  right: Right,
  keys: Keys[]
): { 
  left: Left
  right: Right
}  {
  // ...
}

However, now I get the complaint that the types Left[Keys] and Right[Keys] do not overlap. Which I don't fully get.

Any hints or ideas?


Solution

  • A weird solution but it seems to work in the simple example.

    Playground Link

    function myFunc<
        L extends Pick<R, (keyof R & keyof L)>,
        R extends Pick<L, (keyof R & keyof L)>,
        K extends (keyof R & keyof L)>
        (left: L, right: R, keys: K[]): { left: L, right: R }
    {
        for (const key of keys) {
            console.log(key, left[key] === right[key])
        }
    
        return { left, right }
    }
    
    const left = { a: 1, b: 2, c: 4 };
    const right = { b: 2, c: 3, d: 5 };
    
    // Work:
    myFunc(left, right, [ 'b' ]);
    myFunc(left, right, [ 'b', 'c' ]);
    
    // Error: Type '<>' is not assignable to type '"b" | "c"'.
    myFunc(left, right, [ 'a' ]);
    myFunc(left, right, [ 'd' ]);
    myFunc(left, right, [ 'z' ]);
    

    However it does seem to have some problems if the types of the values corresponding to the overlapping keys don't match. Might be a tricky way to fix it.

    Overall it might just be best to turn off type checking for that one === line if possible.