Announcing: Mapped Types + Pick, Omit, and Record

Jordan Brown
Flow
Published in
2 min readAug 6, 2024
Photo by Mihis Alex on pexels.com

tl;dr: Mapped types allow you to transform object types into other object types. We have added definitions for Pick, Omit, and Record utility types to our library definitions. Docs here.

Mapped Types are enabled by default as of Flow v0.212. To use them, make sure you are following our recommended setup in our docs. Mapped Types (inspired by TypeScript) provide an elegant syntax for transforming object types:

type Obj = {
foo: number,
bar: string,
baz: boolean,
};

type Accessor<+T> = () => T;

type ObjWithAccessors = {[key in keyof Obj]: Accessor<Obj[key]>};

function f(o: ObjWithAccessors): number {
return o.foo();
}

In this example, ObjWithAccessors is a Mapped Type that turns each property of Obj into a function returning the type defined in Obj. It does this all without requiring you to list out the property names again, and changes to the definition of Obj will be reflected in ObjWithAccessors.

We’ve also implemented the highly requested utility types Pick, Omit, and Record using Mapped Types and Conditional Types. We’ve added them to our library definitions.

Mapped Types bring several improvements over $ObjMap, our previous solution for mapping object types:

  1. The syntax is cleaner and easier to both read and write
  2. The expressive power is increased, allowing you to add optionality and variance modifiers in addition to the value type transformation
  3. The underlying representation is crisp and principled, which creates a more reliable and consistent experience

You can find documentation for the feature on our website.

Basic Usage

Mapped Types have syntax similar to indexed object types but use the in keyword:

type O = {foo: number, bar: string};
type Boxify<T> = {contents: T};
type MappedType = {[key in keyof O]: Boxify<O[key]>};

Combined with the keyof keyword, MappedType has all of the keys from O with all of the value types transformed by Boxify<O[key]>. The key variable is substituted for each key in O when creating the property, so this type evaluates to:

{
foo: Boxify<O['foo']>,
bar: Boxify<O['bar']>,
}
= {
foo: {contents: number},
bar: {contents: string},
}

In addition to transforming the value types, you can also add optionality and variance modifiers:

type ReadOnlyOptionalBoxes = {+[key in keyof O]?: Boxify<O[key]>};
// = {+foo?: {contents: number}, +bar?: {contents: string}

Generating Objects from Keys

You can also use mapped types to turn a string literal union into an object type by using in with a union of valid key types (no keyof needed!)

type Union = 'mapped' | 'types' | 'rock';
type Obj = {[key in Union]: number};
// = {mapped: number, types: number, rock: number}

--

--

Flow
Flow

Published in Flow

The official publication for the Flow static type checker for JavaScript. Code faster. Code smarter. Code confidently.

No responses yet