【问题标题】:Type check with typeof === custom type with Flow error使用 typeof === 带有 Flow 错误的自定义类型进行类型检查
【发布时间】:2021-07-09 17:23:00
【问题描述】:

给定以下代码:

type CustomTypeA = {
  x: number,
  y: number,
}

type CustomTypeB = CustomTypeA & {
  z: number,
}

type CustomType = CustomTypeA | CustomTypeB

export const myFunction = (a: CustomType | number): number | void => {
  if (typeof a === 'number') {
    return a; // THIS WORKS WELL, it's considered number after the check, which is correct
  } else if (typeof a === CustomType) {
    
    const newX = a.x // ERR: Flow: Cannot get `a.x` because property `x` is missing in `Number`
    const newZ = a.z // SAME ERR, Flow: Cannot get `a.z` because property `z` is missing in `Number`.
  }
}

此外,typeof a === CustomType 检查也会突出显示为错误:

Flow: Cannot reference type `CustomType` from a value position.

typeof a === 'number' 不会发生这种情况。

这就像对我创建的自定义对象类型的检查无效/无法识别。

有人可以解释为什么以及可能如何逃避这种情况吗? 谢谢。

【问题讨论】:

    标签: object types reference flowtype


    【解决方案1】:

    流自定义类型不是值,它们不存在,它们在编译后消失,因此您不能将它们与 typeof 之类的 JS 运算符一起使用,因为它需要一个值。所以当你做typeof a === CustomType它会失败,因为编译后你将以typeof a === 结尾,CustomType只是被剥离出来,你以无效的JS结尾。

    说实话,这似乎是一个流量限制。

    %checks 运算符允许您构建类型保护函数。 有人可能认为您可以使用此功能通过具有适当逻辑的函数为自定义类型构建类型细化,但其文档中没有任何内容表明它可用于细化自定义类型。 它还要求保护函数的主体非常简单,以便流程可以理解您的意思。一些类型保护函数示例可能如下所示 (from flow docs):

    function truthy(a, b): boolean %checks {
      return !!a && !!b;
    }
    
    function isString(y): %checks {
      return typeof y === "string";
    }
    
    function isNumber(y): %checks {
      return typeof y === "number";
    }
    

    但是,当您尝试更复杂的检查时,例如检查某个对象是对象,但它不是数组或日期,流程无法理解您的意图,谓词函数将不起作用。像这样的:

    function isObject(obj: mixed): boolean %checks {
      return Object.prototype.toString.call(obj) === '[object Object]'
    }
    

    将失败,因为流程不将其理解为对象的类型细化。对于这种特殊情况,有一个 workaround suggested on a github issue 包括在类型级别声明函数,断言它检查对象类型:

    declare function isObject(obj: mixed): boolean %checks(obj instanceof Object)
    

    但是你不能在你的特殊情况下使用它,因为你不能对自定义类型执行 instanceof,因为它不是一个类。

    因此,您的选择要么变得冗长,要么检查类型检查中是否存在所有预期的属性,如下所示:

      if (typeof a.x === 'number' && typeof a.y === 'number' && typeof a.z === 'number') {
        const {x: ax, y: ay, z: az} = a
        // now you can safely use the extracted variables
    

    请注意,您需要从对象中提取 props,因为任何时候调用函数流都会使您的类型优化无效,并且访问 a.x 的下一行将失败。

    您可以将您的观点声明为一个类,并使用类型系统检查该类的实例。

    或者您构建一个返回正确类型或 null 的验证函数,因此 flow 可以理解类型已被优化:

    function isCustomType (p: mixed): CustomType | null {
      const validated = ((p:any):CustomType)
      if (typeof validated.x === 'number' && typeof validated.y === 'number') return validated
      return null
    }
    
      const validA = isCustomType(a)
      if (validA) {
        const {x: ax, y: ay} = validA
        // do stuff
    

    这有一个缺点,您需要分配额外的变量来满足类型系统,但我认为这是一个小问题。 此外,它不允许 flow 为您验证 isCustomType 函数,因为我们正在进行类型转换以基本上欺骗 flow。但是考虑到表面很小并且目标非常集中,能够手动保持正确应该没问题。

    【讨论】:

      猜你喜欢
      • 2020-07-13
      • 2019-01-02
      • 2014-07-10
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      相关资源
      最近更新 更多