Announcing Partial & Required Flow utility types + catch annotations

George Zahariev
Flow
3 min readMar 15, 2023

--

Starting in Flow version 0.201, make an object type’s fields all optional using Partial<ObjType> (use instead of the unsafe $Shape), and make an object type’s optional fields required with Required<ObjType>. Also, you can now annotate a catch variable with mixed.

Partial<T>

The Partial utility type converts all of an object or interface’s fields to be optional. For example:

type Person = {
name: string,
age: number,
};
type PartialPerson = Partial<Person>;
// Above equivalent to `{name?: string, age?: number}`

const a: PartialPerson = {}; // OK
const b: PartialPerson = {name: 'George'}; // OK
const c: PartialPerson = {name: 'George', age: 123}; // OK

This utility replaces the unsafe $Shape utility: use Partial now instead.

Note: while this is the first time we have announced the Partial utility type, it has existed for a while, and had the name $Partial. You should codemod any existing $Partial usages to Partial. We will remove support for the old alias $Partial from version 0.203.

No longer in love with the $Shape of U

Why use Partial instead of $Shape? $Shape allows you to unsafely use $Shape<U> as U in some contexts, for example:

type PersonShape = $Shape<Person>;
const personShape: PersonShape = {name: 'George'};
const person: Person = personShape; // Unsafe - doesn't have `age` prop
const age: number = person.age; // Unsafe - actually `undefined`

It is also not equivalent to itself in some contexts:

function f<U>(input: $Shape<U>): $Shape<U> {
return input; // ERROR: `U` is incompatible with `$Shape` of `U`
}

Partial does not have any of these problems - use it instead!

We will remove support for $Shape from version 0.203 or later.

Required<T>

The Required utility type is the opposite of Partial: it converts all of an object or interface’s optional fields to be required. For example:

type PartialPerson = {
name?: string,
age?: number,
};
type Person = Required<PartialPerson>;
// Above equivalent to `{name: string, age: number}`

const a: Person = {name: 'George', age: 123}; // OK
const b: Person = {age: 123}; // ERROR: missing `name` property

Migrate your $Shape and $Partial usage

We will remove support for $Shape from version 0.203 or later. You should codemod any instances of it to Partial. This may cause new errors, due to the safety issues of $Shape described above. In some contexts $ReadOnly<Partial<T>> may be a better replacement for $Shape<T>, you can try and see if that causes less errors than just Partial<T>.

You can either use flow-upgrade or just regular expressions to codemod your codebase.

Flow upgrade:
Get at least version 2.2.0 of flow-upgrade and run

  • $Shape to Partial: yarn run flow-codemod convertShapeToPartial
  • $Partial to Partial: yarn run flow-codemod renamePartial

Regular expressions:

  • $Shape to Partial: sed -i 's/\$Shape</Partial</g'
  • $Partial to Partial: sed -i 's/\$Partial</Partial</g'

Bonus feature: Catch variable annotations

You can now annotate catch variables as exactly either any or mixed. Without an annotation they continue to be typed as any as before. By using mixed, you can improve your safety and Flow coverage, at the trade-off of increased runtime checks:

try {
danger();
} catch (e: mixed) {
if (e instanceof MyError) {
handleMyError(e);
} else if (e instanceof Error) {
handleError(e);
} else {
throw e;
}
}

You can choose to make mixed the default type of catch variables by enabling the option use_mixed_in_catch_variables=true in your .flowconfig [docs].

--

--