【问题标题】:Flow error when using dynamic function references使用动态函数引用时出现流量错误
【发布时间】:2019-03-14 13:27:38
【问题描述】:

我在一个 React 项目中有一个函数,它遍历一个数组并将每个项目与另一个变量进行比较。现在数组中的项目可以是字符串或正则表达式。所以我保留了一个名为compareFn 的变量,并根据项目的类型将其引用指向equalpatternMatch。下面是示例代码。

const equal = (privilege: string, whitelistVal: string) => privilege === whitelistVal;
const patternMatch = (privilege: string, whitelistPattern: RegExp) => whitelistPattern.test(privilege);

...

const compareFn = whitelistItem instanceof RegExp ? patternMatch : equal;
if (compareFn(privilegeItem, whitelistItem)) {
  // Do something
}

使用此代码,我在第 36 行中收到一个突出显示 whitelistItem 的流错误,如下所示:

无法在 whitelistItem 绑定到 whitelistPattern 的情况下调用 compareFn 因为字符串 [1] 与 RegExp [2] 不兼容。

35| const compareFn = whitelistItem instanceof RegExp ? 模式匹配:相等;
36| if (compareFn(privilegeItem, whitelistItem)) {

在我看来,Flow 似乎无法识别函数引用的条件赋值。感谢您为解决此问题提供任何帮助。

我正在使用 Flow 0.71.0 和 React Native 0.55.3。

【问题讨论】:

  • 如果您使用var 而不是const,您会得到同样的错误吗?还可以考虑将条件测试用括号括起来:(whitelistItem instanceof RegExp) ? ...
  • 两个选项出现相同的错误
  • stackoverflow.com/questions/41328728/… - 这可能会有所帮助

标签: javascript react-native flowtype


【解决方案1】:

以下是可行的:

const equal = (privilege: string, whitelistVal: string) => privilege === whitelistVal;
const patternMatch = (privilege: string, whitelistPattern: RegExp) => whitelistPattern.test(privilege);


declare function getCompareFn(
  whitelistItem: RegExp
): (string, RegExp) => boolean;
declare function getCompareFn(
  whitelistItem: string
): (string, string) => boolean;

function getCompareFn(whitelistItem) {
  return whitelistItem instanceof RegExp ? patternMatch : equal;
}

const whitelistItem1 = /test/;
const whitelistItem2 = "test";

const privilegeItem = "test";

getCompareFn(whitelistItem1)(privilegeItem, whitelistItem1);
getCompareFn(whitelistItem2)(privilegeItem, whitelistItem2);

链接到Try Flow

Flow 的declare 用于确定getCompareFn 的精确类型签名,否则难以表达。注意流程不会强制您声明的正确性,因此您有责任仔细分析并确保声明的类型确实与函数的实现相匹配,尽管在此示例中,这是相当微不足道的。

不使用declare,我们可以这样做:

// type alias to represent generic compare function
type CompareFn<T> = (string, T) => boolean;

function getCompareFn(
  whitelistItem: RegExp | string
): CompareFn<string> | CompareFn<RegExp> {
  return whitelistItem instanceof RegExp ? patternMatch : equal;
}

到目前为止一切顺利,它会进行类型检查。 (但请注意,getCompareFn 的返回值不是CompareFn&lt;RegExp | string&gt;)。不幸的是,getCompareFn 的这种类型规范不够精确。例如,我们知道以下是正确的:

const f: CompareFn<string> = getCompareFn('string');

然而,flow 不能断言。

更进一步,我们可能会尝试这样做来解决问题:

function getCompareFn<T: RegExp | string>(whitelistItem: T): CompareFn<T> {
  return whitelistItem instanceof RegExp ? patternMatch : equal;
}

这比上面的要好得多,因为它更精确,通用函数getCompareFn 状态:

  1. getCompareFn(string) -&gt; CompareFn&lt;string&gt;
  2. getCompareFn(RegExp) -&gt; CompareFn&lt;RegExp&gt;

这正是代码的意图。一切都很好?不幸的是,这段代码没有进行类型检查。问题是T: string | RegExp,它指出:对于string | RegExp 类型的所有子类型,getCompareFn 返回CompareFn&lt;T&gt;。翻译为:

  1. getCompareFn(string) -&gt; CompareFn&lt;string&gt;
  2. getCompareFn(RegExp) -&gt; CompareFn&lt;RegExp&gt;
  3. getCompareFn(string | RegExp) -&gt; CompareFn&lt;string | RegExp);

最后一种情况显然不正确,因为getCompareFn 永远无法返回同时接受字符串和正则表达式的比较函数。所以我们想表达案例1和2,但不允许案例3,我知道这样做的唯一工具是declare,因此解决方案首先在这个答案中概述。

最后,通过稍微更改代码,这是一个不使用declare 的解决方案,并且更习惯用法(在我看来):Link

const whitelistItem1 = /test/;
const whitelistItem2 = "test";

const privilegeItem = "test";

interface TestString {
  test(s: string): boolean;  
};

// RegExp has method `test`, therefore structurally implements TestString

class EqualsString implements TestString {
   _value: string;
   constructor(value: string) {
      this._value = value; 
   }
   test(s) {
      return s === this._value; 
   }
}

function getStringTester(whitelistItem: string | RegExp): TestString {
  if (whitelistItem instanceof RegExp) {
    return whitelistItem;
  } else {
    return new EqualsString(whitelistItem);
  }
}

const t1 = getStringTester(whitelistItem1);
const t2 = getStringTester(whitelistItem2);

const b1: boolean = t1.test(privilegeItem);
const b2: boolean = t2.test(privilegeItem);

【讨论】:

    猜你喜欢
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多