Exhaustive switch in Flow
The static type checker FlowType supports the algebraic data types by encoding sums with disjoint unions of objects. However, Flow does not check if a switch
over a disjoint union is exhaustive. We present a trick to detect at compile-time these non-exhaustive switch
. Thus we can make sure that we do not miss any cases before putting our code into production.
The Gist
Our trick relies on a special Empty
type:
You can try this example on TryFlow. If you add a third case:
you will get the following error:
How does this work?
For each case
of a switch
, Flow refines the type of the value
according to the current case
. For example, in:
the value
is known to be the string 'a'
. In a default
case, the type of value
is refined to the remaining cases or to any
if the switch
is exhaustive. One approach to handle this impossible value
of type any
is to raise an exception:
This is dangerous, because if our Flow program is not 100% typed we could still run into the default
branch and get an uncaught exception into production. Instead, we report the error and return a default value:
Our aim is to generate a Flow error if and only if the switch
is not exhaustive, that is to say if and only if the parameter impossible
of the function unexpectedCase
has type any
. We achive that by introducing a type which has no elements:
This type is empty because there are no strings which are both equal to 'empty type'
and to 'nothing there'
. Thus, the only way to obtain a value of type Empty
is to cast a value of type any
, which is exactly what we are looking for. Hence the function:
will do the trick to force the switch
to be exhaustive.
Related
In most functional languages, destructuring a sum type without being exhaustive raises an error or a warning. In Flow, Adam Solove gives an alternative trick to solve the exhaustiveness problem of the switch
. However, this alternative technique does not work in some conditions (if the return type of the function is string
) and does not return a safe default value. In our experience, it is important to return a valid default value because most Flow programs rely on untyped third-party libraries. Thus it happended to us to go through supposedly impossible default
in production, so it is better to get a log report than to risk a runtime error.
Comments