Infer base type for two arguments in Typescript

Viewed 32

While implementing a generic function on sets in Typescript, I noticed that the compiler is unable to infer the base type of two arguments.

function union<T>(first: Set<T>, second: Set<T>): Set<T> {
  const newSet = new Set<T>(first);
  for (const element of second)
    newSet.add(element);
  return newSet;
}

class Animal { }
class Dog extends Animal {
  bark() { console.info('Woof!'); }
}
class Cat extends Animal {
  meow() { console.info('Meow!'); }
}

const a = new Set<Dog>();
const b = new Set<Cat>();

Then if I call union, Typescript is unable to infer that T should be Animal.

const c = union(a, b);
// This results in the error:
// Argument of type 'Set<Cat>' is not assignable to parameter of type 'Set<Dog>'.
// Property 'bark' is missing in type 'Cat' but required in type 'Dog'.ts(2345)

But if I explicitly call union with T = Animal, it works fine:

const d = union<Animal>(a, b);

What am I doing wrong?

1 Answers

Try yo use union of types:

function union<T extends Animal, U extends Animal>(first: Set<T>, second: Set<U>) {
    const newSet = new Set<T | U>(first);
    for (const element of second)
        newSet.add(element);
    return newSet;
}

class Animal { }

class Dog extends Animal {
    bark() { console.info('Woof!'); }
}
class Cat extends Animal {
    meow() { console.info('Meow!'); }
}

const a = new Set<Dog>();
const b = new Set<Cat>();

const c = union(a, b);

Playground

Adding extra generic argument U helps TS to infer the type of both Set

Related