Home > Software engineering >  Overloading doesn't work with curry function
Overloading doesn't work with curry function

Time:07-12

I'm trying to get return type based on exact string from parameter.

Here is what I have so far (without curring):

type Simple = {
  (side: 'left'): boolean;
  (side: 'right'): number;
};

const simple: Simple = (side: 'left' | 'right') =>
  (side === 'left' ? random([true]) : random([1])) as boolean & number;

const simpleLeft = simple('left'); // boolean ✔️
const simpleRight = simple('right'); // number ✔️

Then I just add curring and it doesn't work anymore

type Hard = {
  (): (side: 'left') => boolean;
  (): (side: 'right') => number;
};

const hard: Hard = () => (side: 'left' | 'right') =>
  (side === 'left' ? random([true]) : random([1])) as boolean & number;

const hardLeft = hard()('left'); // boolean ✔️
const hardRight = hard()('right'); // boolean ❌

random function is there to just get generic type like boolean instead of false or true

const random = <T>(array: T[]) =>
  array[Math.floor(Math.random() * array.length)] as T;

Code above is just an example demonstrating problem, I can't just not use curring because it is a part of big code base

CodePudding user response:

I am not sure why you need currying here. But if you want this to compile correctly you need to put the function overload inside the first function signature.

type Hard = {
  (): {
    (side: 'left'): boolean;
    (side: 'right'): number;
  }  
};

Now the compiler can decide which overload to choose based on the input of the second function.

const hardLeft = hard()('left'); // boolean ✔️
const hardRight = hard()('right'); // number ✔️

Playground

CodePudding user response:

That type Hard just looks like an invalid function overload to me. When evaluating hard(), there is no way for the compiler to infer which of the two signatures you're referring to.

I don't know if it fits your needs, but you could use a generic constraint with a conditional type:

type Hard = {
  (): <T extends 'left' | 'right'>(side: T)
    => T extends 'left' ? boolean :
       T extends 'right' ? number : never;
};

const hard: Hard = () => (side: 'left' | 'right') =>
  (side === 'left' ? random([true]) : random([1])) as boolean & number;

const hardLeft = hard()('left'); // boolean ✔️
const hardRight = hard()('right'); // number ✔️

const random = <T>(array: T[]) =>
  array[Math.floor(Math.random() * array.length)] as T;
  • Related