如何在Flow中注释具有多个可能的调用签名的函数?

时间:2017-04-28 19:23:13

标签: javascript flowtype

在JavaScript中,通常有一种可以多种方式调用的函数 - 例如少数位置参数单个选项对象两者的某种组合。

我一直试图弄清楚如何注释这个。

我试过的一种方法是将rest args注释为各种可能元组的联合:

type Arguments =
  | [string]
  | [number]
  | [string, number]
;

const foo = (...args: Arguments) => {
  let name: string;
  let age: number;

  // unpack args...
  if (args.length > 1) {
    name = args[0];
    age = args[1];
  } else if (typeof args[0] === 'string') {
    name = args[0];
    age = 0;
  } else {
    name = 'someone';
    age = args[1];
  }

  console.log(`${name} is ${age}`);
};

// any of these call signatures should be OK:
foo('fred');
foo('fred', 30);
foo(30);

以上片段是人为的;我可能只是在这个例子中使用(...args: Array<string | number>),但是对于更复杂的签名(例如涉及可以单独或使用先前args的类型化选项对象),能够定义精确的有限集合是有用的。可能的呼号。

但上面没有打字。您可以在tryflow中看到一堆令人困惑的错误。

我也尝试将函数本身键入单独的整个函数defs的联合,但是didn't work

type FooFunction =
  | (string) => void
  | (number) => void
  | (string, number) => void
;

const foo: FooFunction = (...args) => {
  let name: string;
  let age: number;

  // unpack args...
  if (args.length > 1) {
    name = args[0];
    age = args[1];
  } else if (typeof args[0] === 'string') {
    name = args[0];
    age = 0;
  } else {
    name = 'someone';
    age = args[1];
  }

  console.log(`${name} is ${age}`);
};

// any of these call signatures should be OK:
foo('fred');
foo('fred', 30);
foo(30);

如何处理带有多个可能的呼叫签名的类型注释函数? (或者,多重签名被认为是Flow中的反模式,我根本不应该这样做 - 在这种情况下,与第三方库进行交互的推荐方法是什么?)

2 个答案:

答案 0 :(得分:6)

您可以通过将&

加入来定义多个功能签名
type Foo =
  & ((string | number) => void)
  & ((string, number) => void)

Try it.

答案 1 :(得分:1)

在你给出的三种可能的训练中,我已经找到了如何使用单个选项对象使其工作,但是因为你需要设置至少一个对象,你需要定义每种可能性。

像这样:

type Arguments = 
    {|
        +name?: string,
        +age?: number
    |} |
    {|
        +name: string,
        +age?: number
    |} |
    {|
        +name?: string,
        +age: number
    |};

const foo = (args: Arguments) => {
  let name: string = args.name ? args.name : 'someone';
  let age: number = typeof args.age === 'number' && !isNaN(args.age) ? args.age : 0;
  console.log(`${name} is ${age}`);
}

// any of these call signatures are OK:
foo({ name: 'fred' });
foo({ name: 'fred', age: 30 });
foo({ age: 30 });

// fails
foo({});