Typescript Utility Types: Required<T>

Introduction

The Typescript Required<T> utility type provides a wonderful means converting optional properties to be mandatory instead.

Let’s dive into an example to better understand the problem it solves!

Problem Example

interface Person {
    name: string
    email?: string
}

We define an interface called Person with two properties. A mandatory string name property and an optional string email property.

Let’s define a function that accepts an instance of Person as an argument.

const printPerson = (person: Person) => {
    console.log(`Name: ${person.name}`)
    console.log(`Email: ${person.email}`)
}

Brilliant!

Let’s instantiate a Person instance and pass it to the function printPerson.

const person: Person = {
    name: "Jamie"
}

printPerson(person)

We create an instance of Person with an undefined email value. This is perfectly valid since the Person interface is defined with an optional email property.

As you can imagine, this can lead to some unexpected outputs since our printPerson function assumes the presence of an email value (instead of undefined).

Well how can we solve this problem?

One possible solution would be adding a guard clause to the printPerson function that checks for a valid email value.

const printPerson = (person: Person) => {
    if (!person.email) {
        throw new Error("You must provide an email")
    }

    console.log(`Name: ${person.name}`)
    console.log(`Email: ${person.email}`)
}

This seems tedious!

Another, possible solution would be to define another interface. One that looks exactly like Person except for a mandatory email property. We could then change the printPerson function signature to instead accept an instance of the new interface.

interface PersonRequired {
    name: string
    email: string
}

This certainly looks like a better solution. However, it seems even more tedious.

I wonder if we could achieve this without the need to define a new, almost identical interface…?

Enter the Required<T> utility type to save the day!

Solution

The Required<T> utility type converts all optional properties of a type to mandatory!

const printPerson = (person: Required<Person>) {
    console.log(`Name: ${person.name}`)
    console.log(`Email: ${person.email}`)
}

And there you have it!

By simply defining the type of the Person argument in the printPerson function signature as Required<Person> we have provided a means to mark all the optional properties of that Person instance as mandatory.

This certainly looks a lot cleaner while at the same time reducing the amount of code we’d have to write to ensure type-safety.

We also get the added benefit of compile time error checking supporting our efforts to write more robust and less error-prone code.

Conclusion

The Required<T> utility type provides a neat way for us to write type-safe code, with compile time error checking without needing to write guard clauses or define almost identical interfaces.

0
Subscribe to my newsletter

Read articles from Wendel Fabian Chinsamy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Wendel Fabian Chinsamy
Wendel Fabian Chinsamy

Hello! I'm Wendel. A software engineer from Johannesburg, South Africa. I'm very passionate about learning and teaching and I'm using this platform as an opportunity to document my rise through the world of JavaScript. Join me!