Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Flow be forced to cast a value to another type?

Is it possible to forcibly cast a variable in Flow?

type StringOrNumber = string | number const foo: StringOrNumber = 'hello'  // I look for something like `const bar:string = (string) foo` const bar: string = foo // fails const bar: string = (foo: string) // also fails 
like image 852
czerny Avatar asked Dec 26 '16 09:12

czerny


People also ask

How do you cast in flow?

Type Cast Expression Syntax In order to create a type cast expression around a value , add a colon : with the Type and wrap the expression with parentheses ( ) . Note: The parentheses are necessary to avoid ambiguity with other syntax. Type cast expressions can appear anywhere an expression can appear.

How do you cast type in python?

Casting in python is therefore done using constructor functions: int() - constructs an integer number from an integer literal, a float literal (by removing all decimals), or a string literal (providing the string represents a whole number)

What is casting explain the type conversion?

1. In type casting, a data type is converted into another data type by a programmer using casting operator. Whereas in type conversion, a data type is converted into another data type by a compiler.

What does it mean to cast variables?

Type casting means taking an Object of one particular type and “turning it into” another Object type. This process is called type casting a variable. This topic is not specific to Java, as many other programming languages support casting of their variable types.


2 Answers

Flow doesn't do direct casting from one type to another, but you can do something like

const bar: string = (foo: any); 

so you cast foo to an any, because any accepts any type of value as an input. Then because the any type also allows you to read all possible types from it, you can assign the any value to bar because an any is also a string.

like image 174
loganfsmyth Avatar answered Sep 30 '22 14:09

loganfsmyth


In the example you give you're looking at a "cast" from a union type to one of its members. While it's common to think of this as a cast, it's not the same as type-casting in other languages.

By setting the type of foo to string | number, we've told Flow that this value could be either a string or a number. We then happen to put a string in it, but Flow doesn't discard our direct assertion about its type because of that, even in situations (like this one) where it couldn't change later.

To assign it to a string-typed variable, Flow needs to know that even though it might have been either a string or number, by the time we do the assignment we are sure that it can only be a string.

This process of reducing the possible options is called type refinement.

Type refinements

To refine the type, we need to prove that it must be the type we say it is, in a way Flow understands.

In the original example, you could do this using typeof:

type StringOrNumber = string | number const foo: StringOrNumber = 'hello'  // This would raise an error here: // const bar: string = foo  if (typeof foo === "string") {   // Flow now knows that foo must be a string, and allows this.   const bar: string = foo } 

Not everything that a human can see as a type refinement is understood by Flow, so sometimes you'll need to look at the refinement docs to see what might make Flow understand it.

Suppression comments

Sometimes there's no way to express the safety of a refinement to Flow. We can force Flow to accept a statement through use of a suppression comment, which will suppress an error Flow would otherwise report. The default suppression comment is $FlowFixMe, but it can be configured to a different comment or comments.

Flow will report an error on the second line of this, reporting that unionValue might be of type 'number':

const unionValue: StringOrNumber = 'seven' const stringValue: string = unionValue 

However, by using a suppression comment, this passes Flow:

const unionValue: StringOrNumber = 'seven' // $FlowFixMe: We can plainly see this is a string! const stringValue: string = unionValue 

One useful feature of suppression comments is that a suppression comment without a following error to suppress is considered an error. If we change the type in the example:

const unionValue: string = 'seven' // $FlowFixMe: Even though this is a string, suppress it const stringValue: string = unionValue 

Now Flow will report an "Unused suppression" error instead, alerting us. This is particularly useful when Flow should be able to recognize a refinement but can't - by using a suppression comment, we're alerted to remove the comment (and gain additional type-safety) if a future version of Flow recognizes the code as type-safe.

Cast-through-any

If you really can't express it in a way that demonstrates its safety to flow, and you can't (or won't) use a suppression comment, you can cast any type to any, and any to any type:

const unionValue: StringOrNumber = 'seven' // Flow will be okay with this: const stringValue: string = (unionValue: any) 

By casting a value to any we're asking Flow to forget anything it knows about the type of the value, and assume whatever we're doing with it must be correct. If we later put it into a typed variable, Flow will assume that must be right.

Cautions

It's important to note that both suppression comments and cast-through any are unsafe. They override Flow completely, and will happily perform completely nonsensical "casts":

const notAString: {key: string, key2: number} = {key: 'value', key2: 123} // This isn't right, but Flow won't complain: const stringValue: string = (notAString: any) 

In this example, stringValue is holding the object from notAString, but Flow is sure that it's a string.

To avoid this, use refinements that Flow understands whenever you can, and avoid use of the other, unsafe "casting" techniques.

like image 35
Jason Wodicka Avatar answered Sep 30 '22 15:09

Jason Wodicka



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!