flowtype:如何通过参数 count/types 重载函数 return 类型?

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

我想定义一个重载函数,比如

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

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

以便对这些语句进行类型检查:

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 知道对 first 的第一次调用将导致 n === undefined(因为如果 undefinedn 无效,它会抱怨)并且它知道它随后将采用 if 分支,所以我认为它可以推断出 return 类型是 Item,但我尝试过的一切要么让任何事情通过,要么总是失败。

知道这是否可能吗?提前感谢互联网。

我没有适合您的完整解决方案,但我已经做到了:

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)

&是交集类型,也就是说first必须同时满足both。您可以看到对 first() 的调用按照您想要的方式进行了类型检查。

不幸的是,Flow 目前似乎无法对 first 的正文进行类型检查。请注意,我必须将 return 值转换为 any 以转义类型检查器。如果你愿意放弃在你的函数体中进行类型检查,你至少可以在调用函数的地方得到它。

这可能不适用于您编写 OP 时的最新 Flow 版本,但尝试使用最新版本,我发现您甚至可以在源文件中使用 declare function 以避免可怕的语法((_: void) => number) & ((n: number) => Array<number>).

type Item = number;
const items: Array<Item> = [0, 1, 2, 3, 4];

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

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

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

Try Flow link

对于 class 方法,我发现的唯一方法是使用丑陋的 & 语法单独声明字段类型(无论您之前是否使用 declare字段声明与否):

class Foo {
  foo: ((x: number) => string) & ((x: string) => number)
  foo(x: number | string): number | string {
    if (typeof x === 'number') return String(x)
    else return Number(x)
  }
}

const foo = new Foo()
const a: number = foo.foo('1')
const b: string = foo.foo(2)

Try Flow link