Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Combine function signatures into overload

From a type like this:

type Def = {
  m1(a1: A1, b1: B1): R1
  m2(a2: A2): R2
  m3(a3: A3, b3: B3, c3: C3): R3
}

I would like to compute a type like this:

type F =
  ((name: 'm1', a1: A1, b1: B1) => R1) &
  ((name: 'm2', a2: A2) => R2) &
  ((name: 'm2', a3: A3, b3: B3, c3: C3) => R3)

that is the overloaded function type for a dispatcher method that would be dynamically generated.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I have managed to add the name parameter, i.e.:

type H = {
  m1: (name: 'm1', a1: A1, b1: B1) => R1,
  m2: (name: 'm2', a2: A2) => R2,
  m3: (name: 'm3', a3: A3, b3: B3, c3: C3) => R3,
}

through simple object mapping and the Parameter and ReturnType helpers, but all my attempt at merging this into a single call signature have failed.

(see playground link)

>Solution :

Here’s one possible approach:

type IntersectMethods<T> = {
    [K in keyof T]: T[K] extends (...args: infer A) => infer R ?
    (x: ((name: K, ...args: A) => R)) => void :
    never
} extends Record<string, (x: infer I) => void> ? I : never

This uses conditional type inference and infers intersections instead of unions because the type to infer has been moved to a contravariant position (see Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript for more about variance). It’s essentially the same technique as in Transform union type to intersection type with the wrinkle that we are finding only the methods and prepending a name parameter to each one.

Let’s test it out:

type Def = {
  m1(a1: A1, b1: B1): R1
  m2(a2: A2): R2
  m3(a3: A3, b3: B3, c3: C3): R3
}

type F = IntersectMethods<Def>
/* type F = 
     ((name: "m1", a1: A1, b1: B1) => R1) & 
     ((name: "m2", a2: A2) => R2) & 
     ((name: "m3", a3: A3, b3: B3, c3: C3) => R3)
*/

Looks good!

Playground link to code

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading