Flow tips and tricks, part 1: mixed and any
Problem
From the first reading through the documentation for Mixed Types and Any Types, some of us still weren’t clear on the difference between mixed
and any
.
In addition to that, Flow has another type named Object
(Literal type) that isn’t found in the actual documentation et most Javascript developers assume that this type would match all possible types in the language. Sometimes we can substitue a specific type with Object
to resolve some Flow errors but not always.
So what is the difference between them, where and when to use each of these? Especially if it happens to you to maintain a codebase that has plenty of mixed
, any
and Object
pretty much everywhere.
Explanation
From my point of view:
mixed
type is simply a union of all types (string, number, boolean...)any
type is a dynamic type, it can be anything and anything can be typedany
Let’s walk through some simple examples of mixed
and any
to clarify that.
1st example
There’s no problem because we can assign a value of any type (such as a number in this example) to an any-typed or mixed-typed variable. We say that a value of any type can flow into an any-typed or mixed-typed variable.
2nd example
There’s no problem because a any-typed value can flow into a number-typed variable (a boolean, string… variable are also valid in this case). So it’s too easy to have errors at runtime if we do:
3rd example
So a mixed-typed value can’t flow into number-typed variable (same for boolean, string,…). It is simply because a mixed
could be a number, a boolean or something else. It doesn’t has to be a number.
4th example
Object
is something equivalent to {}
but unlike mixed
, only Object can flow into itself but not other primitive types like string
, number
, boolean
, or function
.
I believe that Object
belongs to literal type category in Flow. We might consider that every object in JavaScript could be instantiated by doingnew Object()
and if we type something as Object
, we can do anything with that thing that we want with a {}
.
In practice
Avoid any
, Object
when possible. They are both completely unsafe.
If a variable is treated as any
, we will loose all advantages of Flow’s type checking. Just keep in mind that Flow is disabled every time we use any
. In practice, we usually see any
in type definition files (hosted on flow-typed) for libraries because they are intended to be used by everyone.
In some cases, we have to cope with data coming from external APIs, some might ask to use any
because we doesn’t really know its format. But no! We still avoid any
in these cases by defining types for the format of the received data and use tcomb or flow-runtime to constantly check the type of it at runtime. If the data format changes one day, we will be notified of by these libraries, in order to adapt the previously defined type to the new format.
What about Object
?
If a variable is treated as Object
, Flow will allow us to access any property on it and do whatever we want with that property. For example :
Like
any
orObject
, I recommend not usingFunction
type, if we know the format of a function, just type it correctly. For example:type Some_Function = () => Promise<void>
is the type of a function that does some asynchronous tasks.
I personally recommend using mixed
to type the output of any function that we think we won’t care about its output later.
If we used mixed
in a variable’s type declaration, we should somehow figure out the exact type of this variable later by using refinement. Sometimes with that we cannot handle all the cases because mixed
is just a union of all possible types. In these cases, we should use disjoint union type instead to have a clear idea about the type definition of a variable then.
Sometimes we use * to have Flow infer the type for us (details here). From version 0.72 and later, we have the possibility to deprecate this type under the
deprecated-type
strict flag. I found some articles trying to explain this type and how it differs frommixed
orany
, but the key point here is that this type is not usually used, and I recommend not using it because one day it could be really deprecated from some version of Flow on and we would have to take time to get rid of it at that time.