javascript - 如何在 Flow 中使用相同泛型类型的值对泛型函数进行类型检查

标签 javascript reactjs generics flowtype

我们将 Flow 与 React 结合使用,并编写了这个 DropDown 包装器来为我们做一些事情。

到目前为止,这个下拉列表只需要使用 number id,但最近,我们还必须添加对 string id 的支持。

不想重写所有内容,我们考虑对 props 使用通用类型参数,以便 id(和 onChange 处理程序)将使用该通用类型。

但是,我们似乎无法正确使用该更改处理程序。尝试调用处理程序时,我们收到有关我们发送的值类型(numberstring)的 Flow 错误,告诉我们此类型不兼容使用 T:

无法调用绑定(bind)到“value”的“handler”,因为字符串 [1] 与“T”不兼容

number 调用也一样。

我们相信,如果我们成功地检查了我们的泛型值之一的类型,它会为我们的 Prop 中使用相同泛型类型的每个元素折叠该类型。他们在这里:

type Props<T : string | number> = {
  options?: Array<{id: T, displayValue: string}>,
  onValueChange?: (value: T | null) => mixed,
}

因为我们知道 Flow 不允许使用这些带有 onValueChange 的 props 创建元素,如果 options 将处理 number包含带有 string 的 id,例如,我们认为通过检查 options 中 id 的类型,我们可以折叠 TonValueChange 也是如此。

这是我们得到错误的地方:

export class DropDown<T : string | number> extends React.Component<Props<T>, {}> {
  handleChange = (event: {target: {value: string}}) => {
    if (!this.props.onValueChange) return
    const handler = this.props.onValueChange

    const firstElement = this.props.options && this.props.options[0]
    if (!firstElement) return

    const value = event.target.value

    // I don't understand why, but this if-else if generates an error.
    if (typeof firstElement.id === 'string') {
      handler(value)
    } else if (typeof firstElement.id === 'number') {
      const num = parseInt(value)
      handler(num)
    }
  }
}

因此,我的问题是:是否可以确定函数参数的泛型类型,以便我们可以按需要使用它而不会出错?

如果答案是肯定的,那么我们的代码中有什么地方做错了,导致类型检查无法正常工作?

如果答案是否定的,是否有比将我们的值转换为 any 更好的方法来让我们的处理程序接受它?

我在这个 Flow Try snippet 中写了一个最小的工作示例,所以你可以看到实时错误,以及预期的用法(请注意,用法部分中的错误是预期的:它们在那里表明使用通用组件可以按照我们想要的方式工作,即使使用值没有)。重要的错误是错误输出中的前两个错误。

预先感谢您的帮助!

最佳答案

感谢这个非常有趣的问题! 不幸的是,我认为现在不可能通过细化数组中第一个元素的类型来细化 T 类型。当我们使用以下语句时可以看出这一点:

if (firstElement) {
  if (typeof firstElement.id === 'string') {
    const refined: string = firstElement.id;
    const notRefined: T = refined; // Errors
    const alwaysWorks: T = firstElement.id;
  }
  const alwaysWorks: T = firstElement.id;
}

第二次赋值错误。有趣的是,这可以通过将第一个赋值标记为 T 来解决,它显示了 Flow 的工作原理:Flow 本身并不细化类型,它细化了值的类型标签。而且我认为您已经正确地得出结论,您需要做的是优化回调函数的值。但这不起作用,因为我们无法对函数进行任何运行时检查(除非可能获取它们的参数数量)。

因此我们了解到 Flow 还不够好。当您更深入地使用 Flow 时,您可能会不时注意到这一点:很难表达您正在尝试做的事情。我不确定是 Flow 出了问题,还是只是 JavaScript 很难输入。无论如何,作为一种解决方案,我想建议您只需使用 Function 注释处理程序变量。 Function 在某种程度上是 any 类型,使函数更通用。我们知道代码有效(请参阅我的更正,进行空检查,然后检查 id 属性而不是对象)并且外部接口(interface)对类型非常明确。有时是 API 很重要,我们必须在内部进行一些修改。这很好(例如,我们可以在流行项目中看到很多 like these 13 cases in graphql-js )

奖励:如果您喜欢函数式编程,请查看如何 this library玩转类型以创建没有运行时开销的 Maybe 类型的错觉,因为它实际上只是 null

关于javascript - 如何在 Flow 中使用相同泛型类型的值对泛型函数进行类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51486988/

相关文章:

javascript - Dygraph.js - 当 x 为日期时获取图表的中心点

javascript - Session.cookies.get_dict() 返回一个空字典

javascript - 使用 jQuery 将鼠标悬停在 div 上时更改背景图像

javascript - 如何通过创建 react 应用启用 JIT(即时模式)?

java - 创建自定义哈希表

javascript - JS中可变时间段平滑增加数字

javascript - 无法在订阅主体内的 setState Hook 中调用先前状态的对象方法

javascript - 你如何在 ReactJS 中悬停? - 快速悬停期间未注册 onMouseLeave

java - 仅包含一种类型的集合

java - 无法使用 Java 泛型将类型 int 转换为 E