Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flowtype: how can i overload function return types by argument count/types?

i want to define an overloaded function like

function first(n?: number) {
  if (number === undefined) {
    // returns a single Item
    return items[0];
  }

  // returns an array of Item
  return items.slice(0, n);
}

so that these statements type check:

const item: Item = first(); // no args, so return type is Item
const items: Array<Item> = first(5); // number arg, so return type is Array<Item>

flow knows that the first call to first is going to result in n === undefined (since it would complain if undefined wasn't valid for n) and it understands that it will then take the if branch, so i would think it could infer the return type is Item, but everything i've tried either lets anything pass or always fails.

any idea if this is possible? thanks in advance internet.

like image 702
nrser Avatar asked Mar 01 '17 18:03

nrser


Video Answer


1 Answers

I don't have a complete solution for you, but I got partway there:

const items = [1, 2, 3];

type FirstType = ((_: void) => number) & ((n: number) => Array<number>);

const first: FirstType = (n?: number) => {
  if (n === undefined) {
    // returns a single Item
    return (items[0]: any);
  } else {
    // returns an array of Item
    return (items.slice(0, n): any);
  }
}

const a: number = first();
const b: Array<number> = first(2);

(tryflow)

The & is an intersection type, and it means that first must satisfy both of those types. You can see that the calls to first() typecheck the way you want.

Unfortunately, it does not seem like Flow is currently able to typecheck the body of first. Note that I had to cast the return values through any to escape the typechecker. If you are willing to forgo typechecking in the body of your function, you can at least get it where the functions are called.

like image 182
Nat Mote Avatar answered Oct 13 '22 00:10

Nat Mote