In 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
Now, what if we want to make another interface that doesn’t require the
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.
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
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
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 make all properties of a type optional.
WeakInterface we implemented before is actually a Partial.
Required is the opposite of Partial. It will mark each property as required.
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 is used to construct a type based on a subset of properties of another type.
Let’s look at an example that use Pick.
obj, we only need to specify the properties
c doesn’t exist on the type generated by Pick.
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
d, both of type string.
That’s it for Mapped Types 🎉. Hope you find it useful.