Flow: check thenable type

I have a function that accepts either thenable (an object that has a then() method, see the top of https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve ) or something else:

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

The thread complains when I refer to value.then in this if . I can fix it with (value: any).then , but it looks hacked.

Can someone recommend a good way to dial this check?

https://tryflow.org/?code=ZnVuY3Rpb24gcmVzb2x2ZTxUPih2YWx1ZToge3RoZW46ICgpPT5UfXxUKSB7CiAgICBpZiAodmFsdWUgJiYgdmFsdWUudGhlbikgewogICAgICAgIGNvbnNvbGUubG9nKCd0aGVuYWJsZScsIHZhbHVlLnRoZW4pOwogICAgfSBlbHNlIHsKICAgICAgICBjb25zb2xlLmxvZygnbm90IHRoZW5hYmxlJyk7CiAgICB9Cn0=

+5
source share
1 answer

Great question! This is what the Flow team has fought over the past few weeks!

What is the problem

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

Inside this if statement is what type of value ? If T is a string , then it will be {then: ()=>T} , as you expect. But what if T { then: string } ? As far as we know, T may have a property called then !

What does the Flow team do to fix this?

  • Adding exact types of objects. This problem arises from the ignorance of whether one branch of the union may or may not have properties. With exact types, you can precisely indicate the streams which properties the objects have.
  • Allow verification of the value.then property and specify the type of value.then - mixed .

Most of this work is already in mastery. You can check flowtype.org/try, which is currently disconnecting from the wizard. Your example at flowtype.org/try

As soon as this material lands (some of them are in v0.31.0 and some of v0.32.0), we will write and publish a blog about it.

edit: add additional information

3 main problems

There are 3 general questions that we are working on resolving.

  • When should we allow value.then in a conditional expression? If we only allow value.then , when we are sure that value has the then property, then we can catch typos like value.tehn . However, idiomatic JavaScript often tests objects for properties that may or may not exist.
  • What is the type of value if the conditional value is true or false. In the above example, value is a union type. It seems that the intent of value && value.then is to determine if the function uses the left branch of the union. However, Flow cannot safely select a branch, since T can have a then field.
  • What is the type of value.then if the conditional value is true or false. Again, T can be an object of type { then: string } , so value.then can be any

Our solutions

When should we allow value.then in conditional

We always allow value.then . This means that we cannot easily intercept property name identifiers, but that means we can support more idiomatic JavaScript. One of the basic principles of Flow is that it works well with JavaScript, which people tend to write.

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

If Flow knows for sure that only one branch type branch will work, it will specify the value type for this branch. Otherwise, value will not be specified. Exact types will help with this.

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

If Flow knows for sure that only one branch type branch will work, it will refine the type value.then to the type of the then property on this branch. If Flow knows for sure that no branch has this property, this will lead to an error. Otherwise, it will use the mixed type. Exact types also help with this.

What are exact types?

{ x: string } is an object type with property x , which is of type string .

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

This is useful for idiomatic JavaScript, but it is difficult for Flow to say that the type of an object does NOT have properties. Therefore, we add exact types.

{| x: string |} {| x: string |} is an object type with property x , which is of type string but has no other properties.

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

This helps because you can write something like this:

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

As soon as we run them, we will record them! So keep your eyes peeled!

+5
source

All Articles