如何在不嵌入文字的情况下创建Flow Union运行时优化

时间:2019-01-11 15:22:25

标签: flowtype

你好,Stackoverflow的人,

我正在尝试创建一个函数来防止代码在运行时由于错误的Flow类型而被执行。

我的理解是,在运行时执行此操作的方法是优化或检查类型是否符合要求,并使用Flow来确保过程中不会遗漏任何情况。

一个简单的例子是我有一个字符串输入,我想确认与一个枚举/联合类型的匹配。我可以像使用文字那样工作,

    /* @flow */

    type typeFooOrBaa = "foo"| "baa"

    const catchType = (toCheck: string): void => {

        // Working check
      if (toCheck === "foo" || toCheck === "baa") {
        // No Flow errors
        const checkedValue: typeFooOrBaa = toCheck 

        // ... do something with the checkedValue
      }
    };

尝试over here

自然,我想避免嵌入文字。

我尝试过的一件事是等效的对象键测试,它不起作用:-(例如

    /* @flow */

    type typeFooOrBaa = "foo"| "baa"
    const fooOrBaaObj = {"foo": 1, "baa": 2}


    const catchType = (toCheck: string): void => {

      // Non working check
      if (fooOrBaaObj[toCheck]) {
        /*
        The next assignment generates the following Flow error

        Cannot assign `toCheck` to `checkedVariable` because: Either string [1] is incompatible
        with string literal `foo` [2]. Or string [1] is incompatible with string literal `baa` [3].",
            "type"
        */
        const checkedVariable: typeFooOrBaa = toCheck  
      }  
    };

尝试over here

是否有可能实现这样的事情而不必走完整的flow-runtime路线?如果是这样,最好怎么做?

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

您可以将对象键入为{[fooOrBaa]: number},但是流程不会强制fooOrBaa的所有成员都存在于对象中。

答案 1 :(得分:0)

一种可行的方法是使用定义允许值的const对象:

  1. 使用$ keys实用程序生成联合类型。
  2. 使用该联合类型创建一个地图对象,其中的键是所需的输入(我们的案例字符串),而值是需要精炼的“也许”类型。

下面是修改后的示例,以便进行修改:

  • 按照我们希望允许“ foo”或“ baa”的方式设置类型,但别无其他。
  • 检测适当地细化字符串以使其仅包含“ foo”或“ baa”的情况。
  • 检测字符串何时可能包含预期之外的其他内容。

为他的@vkurchatkin致谢answer,这帮助了我(最终)。

/* @flow */

// Example of how to persuade Flow to detect safe adequately refined usage of a Union type 
// at runtime and its unsafe, inadequately refined counterparts.

const fooOrBaaObj =  {foo: 'foo', baa: 'baa'}

type typeFooOrBaa = $Keys<typeof fooOrBaaObj>
// NB: $Keys used inorder for the type definition to avoid aliasing typeFooOrBaa === string 
// which allows things like below to correctly spot problems.
//const testFlowSpotsBadDefition: typeFooOrBaa = "make_flow_barf"


const fooOrBaaMap: { [key:  string]: ?typeFooOrBaa } = fooOrBaaObj;
// NB: Use of the "?" maybe signifier in the definition a essential to inform Flow that indexing into 
// the map "might" produce a "null". Without it the subsequent correct detection of unsafe
// unrefined variables fails.



const catchType = (toCheck: string): void => {     
  const myValue = fooOrBaaMap[toCheck];
  if (myValue) {
    // Detects refined safe usage
    const checkedVariable: typeFooOrBaa = myValue  
  } 
  // Uncommenting the following line correctly causes Flow to flag the unsafe type. Must have the
  // "?" in the map defininiton to get Flow to spot this.
  //const testFlowSpotsUnrefinedUsage: typeFooOrBaa = myValue  
}

here上玩耍