流程:检查 thenable 的类型

Flow: check type of thenable

我有一个接受 thenable(具有 then() 方法的对象;参见 MDN JavaScript docs: Promise.resolve() 的顶部)或其他东西的函数:

function resolve<T>(value: {then: ()=>T}|T) {
    if (value && value.then) {
        console.log('thenable', value.then);
    } else {
        console.log('not thenable');
    }
}

Try Flow demo

当我在此 if 语句中访问 value.then 时,Flow 抱怨。我可以用 (value: any).then 修复它,但这看起来很老套。

任何人都可以推荐一个类型检查的好方法吗?

好问题!这是 Flow 团队在过去几周一直在努力解决的问题!

有什么问题

if (value && value.then) {
  // What is the type of `value` here?
} else

在 if 语句中,value 的类型是什么?如果 Tstring,那么它将是 {then: ()=>T},如您所料。但是如果 T{ then: string } 呢?据我们所知,T 可能有一个名为 then!

的 属性

Flow 团队正在做什么来解决这个问题?

  • 添加确切的对象类型。这个问题来自不知道工会的一个分支是否可能有 属性。使用确切的类型,您可以准确地告诉 Flow 一个对象具有哪些属性。
  • 允许 value.then 属性 检查,并将 value.then 的类型细化为 mixed

这项工作的很多内容已经在 master 中了。您可以查看 flowtype.org/try,它目前在 master 之外运行。 Your example on flowtype.org/try

一旦这些东西落地(一些出现在 v0.31.0 中,一些出现在 v0.32.0 中),我们将对其进行记录和博客。

编辑:添加更多信息

3个主要问题

我们正在努力解决 3 个一般性问题。

  • 我们什么时候应该在条件语句中允许 value.then?如果我们在确定 valuethen 属性 时只允许 value.then,那么我们可以捕捉到像 value.tehn 这样的拼写错误。但是,惯用的 JavaScript 经常测试对象的属性,这些属性可能存在也可能不存在。
  • 如果条件为真或假,value 的类型是什么。在提供的示例中,value 是联合类型。 value && value.then 的目的似乎是检测函数是否正在使用联合的左分支。但是,Flow 不能安全地选择一个分支,因为 T 可能有一个 then 字段。
  • 如果条件为真或假,value.then 的类型是什么。同样,T 可能是一个像 { then: string } 这样的对象,所以 value.then 可能是任何东西

我们的解决方案

When should we allow value.then in a conditional

我们将始终允许 value.then。这意味着我们无法轻易发现 属性 名称拼写错误,但这意味着我们可以支持更多地道的 JavaScript。 Flow 的主要原则之一是它与人们倾向于编写的 JavaScript 配合得很好。

What is the type of value if the conditional is true or false.

如果 Flow 确定只有联合类型的一个分支可以工作,它会将 value 的类型细化到那个分支。否则,value不会被细化。精确类型将对此有所帮助

What is the type of value.then if the conditional is true or false

如果 Flow 确定只有一个联合类型的分支可以工作,它会在该分支上将 value.then 的类型细化为 then 属性 的类型.如果 Flow 确定没有分支具有 属性,它就会出错。否则,它将使用 mixed 类型。精确类型对此也有帮助。

什么是确切类型

{ x: string } 是具有 属性 x 类型的对象的类型 string.

var example1: { x: string } = { x: 'hello' }; // This is ok
var example2: { x: string } = { x: 'hello', y: 123 }; // This is also ok

这对于惯用语 JavaScript 很有用,但是 Flow 很难说一个对象类型没有 属性。所以我们要添加精确类型。

{| x: string |} 是具有 属性 x 的对象的类型,它具有类型 string 但没有其他属性。

var example1: {| x: string |} = { x: 'hello' }; // This is ok
var example2: {| x: string |} = { x: 'hello', y: 123 }; // Error! Extra property y!

这很有帮助,因为您可以这样写:

type Foo = {| x: string |} | {| y: string |};

function test(arg: Foo): string | void {
  if (arg.x) {
    return arg.x;
  }
}

一旦我们推出这些,我们将记录它们!所以请擦亮眼睛!