2

I have an array that contains multiple objects with functions foo.

Now I want to construct a new object signature with a function foo that inherits all signatures from the array item foo functions.

let arr = [
    { foo: (a: 'a') => 'A' as const },
    { foo: (a: 'b') => 'B' as const },
];

type MapAndUnion<T extends ReadonlyArray<any>> = { foo: T[number] extends { foo: infer V } ? V : never }

type U = MapAndUnion<typeof arr>

unfortunately, I am getting

type U = {
    foo: ((a: "a") => "A") | ((a: "b") => "B");
}

This is not callable, as the signatures are conflicting.

Is there a way to get (AND instead of OR)

type U = {
    foo: ((a: "a") => "A") & ((a: "b") => "B");
}

?

playground

phry
  • 35,762
  • 5
  • 67
  • 81
  • 2
    Possible duplicate of [Transform union type to intersection type](https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type) – jcalz Jan 03 '20 at 20:01

1 Answers1

3

You can use type inference in conditional types in a contravariant position to get intersections instead of unions:

type MapAndIntersection<T extends ReadonlyArray<any>> =
  { foo: ((x: T[number]) => void) extends ((x: { foo: infer V }) => void) ? V : never }

type U = MapAndIntersection<typeof arr>
// type U = { foo: ((a: "a") => "A") & ((a: "b") => "B"); }

Hope that helps; good luck!

Link to code

jcalz
  • 264,269
  • 27
  • 359
  • 360