【问题标题】:Flowtype constantly requiring null checksFlowtype 不断需要空检查
【发布时间】:2023-03-13 18:32:01
【问题描述】:

我想知道如何避免这些大量的空检查,或者至少了解重点是什么,因为它似乎适得其反。

如果我省略空值检查,Flowtype 会给我一个错误:

var myEl = new MyElement()
if (document.body != null) { // error on next line if omitted
    document.body.appendChild(myEl)
}

我也必须在每个回调中对文档正文进行空值检查,因为谁知道呢,也许正文在这里是空的,对吧?! 我认为这完全是矫枉过正。不仅如此,如此简单的空检查又有什么意义呢?它只会默默地跳过程序的重要部分,并在其他地方表现出未定义的行为,并使调试应用程序变得更加困难。 如果在这里发生错误,我真的更喜欢此时只有一个空异常,因为要真正确定我用 javascript 编写的这个微小的 2 行代码段在 flowtype 中必须是这样的:

var myEl = new MyElement()
if (document.body != null) {
    document.body.appendChild(myEl)
} else {
    console.error("null error")
}

因此,如果我让应用程序出现错误,那么 4 个额外的代码行和一些嵌套只是为了跟踪我可以免费获得的东西。我需要在每个 querySelector 上使用这 4 行。在每一个 document.body 上。在每一个 getElementByTagName 上。仅此一项就可能使我的整个代码库增加 10%。 如此严格执行有什么意义?

在其他语言中,我也可以根据需要逐渐尝试捕捉这些热点,flow 也不允许我这样做。无论我是否添加 try-catch,它都会显示错误。

【问题讨论】:

  • 您可以使用if (!document.body) throw new Error();,而不是if/else 等。归根结底,Flow 在这里完成了它的工作,它 100% 避免了可能被时间系统捕获的运行时错误。 try/catch 用于捕获显式异常,但 null 检查是类型系统的责任。有些语言确实允许,但 Flow 不允许。
  • @Blub 我问 Flowtype 错误是什么?这可能有助于回答。值得注意的是,Flowtype 可以被视为 Maybe 类型,因此它并不总是 JavaScript 空值。
  • @KevinTomiyoshiYang file: '[flow] 方法调用appendChild(方法不能在可能的空值上调用)'

标签: flowtype


【解决方案1】:

通过使用类型检查器,您选择接受它强制执行的规则。访问可空类型的属性是这些限制之一。所以如果你想对 null 值有异常,你需要显式地 throw 来向 Flow 证明它是你想要的。例如,您可以制作一个类似

的模块
if (!document.body) throw new Error("Unexpectedly missing <body>.");
export const body: HTMLElement = document.body;

export function querySelector(el: HTMLElement, selector: string): HTMLElement {
    const result = el.querySelector(selector);
    if (!result) throw new Error(`Failed to match: ${selector}`);
    return result;
}

通过抛出,这些函数在所有情况下都明确表示“我将返回一个元素”,而在null 情况下,它们将抛出异常。

那么在你的普通代码中,你可以保证你可以使用这些

import {body, querySelector} from "./utils";

body.appendChild(document.createElement('div'));

querySelector(body, 'div').setAttribute('thing', 'value');

它会检查属性。

【讨论】:

  • 另外值得注意的是 Flow 对 invariant 名称进行了特殊处理。您可以import invariant from 'assert' 或以其他方式为invariant 提供实现,然后您可以只写invariant(document.body) 而不是您想出的if/throw 行。打字速度更快,IMO 读起来也更好。
  • invariantinstanceof 一起使用很好,因为它确保了类型而不是 null invariant(document.body instanceof Body)
【解决方案2】:

当我确定我的变量不会为 null 而 Flow 不是时,我使用 unwrap() 函数:

export default function unwrap<T>(value: T): $NonMaybeType<T> {
  if (value !== null && value !== undefined) return value
  throw new Error('Unwrapping not possible because the variable is null or undefined!')
}

【讨论】:

    猜你喜欢
    • 2017-07-31
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 2019-02-09
    • 2021-08-16
    • 2017-08-30
    相关资源
    最近更新 更多