Understanding Mapped Types In TypeScript
Oct 29, 2022 · 5 min readIn this post, we’ll look at Mapped Types in TypeScript.
It’s recommended that you have a basic understanding of generics first before proceeding.
What Is Mapped Type?
A mapped type is a generic type which uses a union of PropertyKeys (frequently created via keyof
) to iterate through keys to create a new type.
Mapped type is easier to explain using examples. Say that we have an interface that look like this:
Any object that implements the interface must have the a
and b
properties.
Now, what if we want to make another interface that doesn’t require the a
and b
properties. We can accomplish it this way.
This look awfully familiar with the RequireAB
interface above. Can’t we just create our NotRequireAB
based on RequireAB
? Of course we can, using Mapped Type.
We created NotRequireAB
based on RequireAB
. The type will contain a property for each property in RequireAB
but with an optional modifier (?
) next to it. We’re basically just creating this code dynamically:
An advantage of using this method to hard-coding is that we don’t need to maintain 2 separate types. In the case where we have to add some more properties to RequireAB
, we don’t need to do it for NotRequireAB
if we created it using mapped type. This will make the code more maintainable.
We can make the type even more powerful with generics.
WeakInterface is a type that take in a type T
and make all the properties optional.
We can use WeakInterface
whenever we need to use an interface but with all the properties optional.
Note that we still can’t define properties that are not available on the original type.
The code above will produce the following error:
Adding And Removing Modifiers
We can add or remove modifiers by prefixing them using the +
or -
operator.
When no operator is specified, TypeScript will assume that it’s +
. That’s why on our WeakInterface
above, we don’t need to specify +
before our ?
modifier.
Now let’s look at an example where we use the -
operator. Say that we want to make our WeakInterface
strong again. We can remove all the ?
modifier like this:
All we have to do is add the -
operator before the modifier.
Introducing Some Predefined Mapped Types
Transforming properties with mapped types is a very common operations that TypeScript provides us with some predefined type definitions.
You can check them out on lib.es5.d.ts.
In this section, we’ll explore some of these type definitions.
Partial
Partial make all properties of a type optional.
Our WeakInterface
we implemented before is actually a Partial.
Required
Required is the opposite of Partial. It will mark each property as required.
Readonly
We can use Readonly mapped type to mark each property as readonly (immutable), as follows:
Readonly is a mapped type that adds a readonly
property to each properties of the type, making the type immutable.
We can also create a type that remove the readonly
modifier, and make the properties mutable again.
Now, Let’s look at an example of using Readonly.
The last line will produce an error as expected.
Pick
Pick is used to construct a type based on a subset of properties of another type.
Let’s look at an example that use Pick.
In obj
, we only need to specify the properties a
and b
. Property c
doesn’t exist on the type generated by Pick.
Record
Record is used to construct a type on the fly. In a way, it’s the opposite of Pick. Record uses a list of properties as a string literal to define what properties the type must have.
Let’s look at an example that use Record.
The type in our obj
is created by passing two generic arguments to the Record type. Record then create a new type with the properties of c
and d
, both of type string.
Wrap Up
That’s it for Mapped Types 🎉. Hope you find it useful.