Skip to main content

Empty

The empty type has no values. It is the subtype of all other types (the bottom type), the opposite of unknown.

1function throwIt(msg: string): empty {2  throw new Error(msg);3}

When to use this

Use empty as the return type of functions that never return (they always throw). You can also cast to empty to assert exhaustiveness — if you've refined away all members of a union, the remaining value should be empty:

1function f(x: 'a' | 'b'): number {2  switch (x) {3    case 'a':4      return 1;5    case 'b':6      return 2;7    default:8      return x as empty;9  }10}

If you had not checked for all members of the union (for example, changed x to be of type 'a' | 'b' | 'c'), then x would no longer be empty in the default, and Flow would error.

Note: If you want exhaustively checked enums by default, without having to cast to empty, you could enable and use Flow Enums in your project.

Since empty is the subtype of all types, all operations are permitted on something that has the empty type. However since no values can be empty, this is "safe", unlike with any.

1const str = "hello";2
3if (typeof str === "string") {4  str as string; // Yes it's a string5} else {6  // Works! Since we will never enter this branch7  str as empty;8  const n: number = str + 1;9}

We put "safe" in quotes above, as due type safety holes in your code or bugs within Flow itself, it is possible to get values which are empty typed.

You can use the coverage command to identify code typed as empty.

See Also

  • Unknown — the supertype of all types (the opposite of empty)
  • Any — an unsafe escape hatch that is both the top and bottom type
  • Type Hierarchy — how empty, unknown, and any relate in the full type hierarchy
  • Unions — casting to empty in a default branch asserts exhaustiveness over union members
  • Match Expressions — pattern matching with built-in exhaustiveness checking