热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在Flow中注释具有多个可能的调用签名的函数?》经验,为你挑选了2个好方法。

在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)在这个例子中使用,但是对于更复杂的签名(例如涉及可以单独或与先前args的类型化选项对象),能够定义一组精确的,有限的可能的呼叫签名将是有用的.

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

我也尝试将函数本身键入为单独的整个函数defs的联合,但这也不起作用:

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中的反模式,我根本不应该这样做 - 在这种情况下,与第三方库进行交互的推荐方法是什么?)



1> EugeneZ..:

您看到的错误是代码中的错误和Flow中的错误的组合.

代码中的错误

让我们从修复你的bug开始吧.在第三个else语句中,您指定了错误的值

  } else {
    name = 'someone';
    age = args[1]; // <-- Should be index 0
  }

将阵列访问权限更改为正确的索引会删除两个错误.我想我们都同意这正是Flow的用途,在代码中发现错误.

缩小类型

为了找到问题的根本原因,我们可以在错误区域更明确,以便我们可以更容易地看到问题所在:

if (args.length > 1) {
  const args_tuple: [string, number] = args;
  name = args_tuple[0];
  age = args_tuple[1];
} else if (typeof args[0] === 'string') {

这实际上和以前一样,但是因为我们非常清楚在这一点上应该做什么args[0]args[1]应该做什么.这给我们留下了一个错误.

Flow中的错误

剩下的错误是Flow中的错误:https://github.com/facebook/flow/issues/3564

bug:元组类型不与长度断言交互(.length> = 2和[] | [number] | [number,number]类型)

如何键入重载的函数

在处理具有不同类型的可变参数时,流程并不是很好,就像在这种情况下一样.Variadics更适用于function sum(...args: Array)所有类型相同而且没有最大arity的东西.

相反,您应该更明确地使用您的参数,如下所示:

const foo = (name: string | number, age?: number) => {
  let real_name: string = 'someone';
  let real_age: number = 0;

  // unpack args...
  if (typeof name === 'number') {
    real_age = name;
  } else {
    real_name = name;
    real_age = age || 0;
  }

  console.log(`${real_name} is ${real_age}`);
};

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

这不会导致错误,我认为开发人员也更容易阅读.

一个更好的方法

在另一个答案中,Pavlo提供了另一种我喜欢的解决方案.

type Foo =
  & ((string | number) => void)
  & ((string, number) => void)

const foo: Foo = (name, age) => {...};

它以更清洁的方式解决了同样的问题,让您更灵活.通过创建多个函数类型的交集,您可以描述调用函数的每种不同方式,允许Flow根据函数的调用方式尝试每个函数.



2> Pavlo..:

您可以通过以下方式连接它们来定义多个功能签名&:

type Foo =
  & ((string | number) => void)
  & ((string, number) => void)

试试吧.


推荐阅读
author-avatar
100斤的重口味_866
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有