Flow tips and tricks, part 1: mixed and any

NGUYEN Trung
4 min readJun 10, 2018

--

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 typed any

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 or Object, I recommend not using Function 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 from mixed or any, 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.

--

--