Skip to content

Avoiding Null and Undefined with NonNullable<T> in TypeScript

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Use Cases

Use Case 1: Adding Two Numbers

Scenario: A function that adds two numbers and returns their sum. But if one of the numbers is undefined or null, it returns the other number as-is.

function addNumbers(a: number, b?: number | null): NonNullable<number> {
  return a + (b ?? 0);
}

const sum1 = addNumbers(2, 3); // Returns 5
const sum2 = addNumbers(2, null); // Returns 2
const sum3 = addNumbers(2, undefined); // Returns 2

In this code snippet, the addNumbers() function takes two parameters, a and b. a is a required parameter of type number, while b is an optional parameter of type number or null. The function uses the NonNullable<T> conditional type to ensure that the return value is not null or undefined. If b is null or undefined, the function returns the value of a. Otherwise, it adds a and b together and returns the sum. To handle the case where b is null or undefined, the code uses the nullish coalescing operator, ??, which returns the value on its left-hand side if it is not null or undefined, and the value on its right-hand side otherwise.

Use Case 2: Checking Contact Information

Scenario: A class representing a person, but with optional email and phone properties. The contact() function logs the email and phone numbers if they are defined and not null. Otherwise, it logs a message saying that no contact information is available.

class Person {
  name: string;
  email?: string | null;
  phone?: string | null;

  constructor(name: string, email?: string | null, phone?: string | null) {
    this.name = name;
    this.email = email ?? null;
    this.phone = phone ?? null;
  }

  contact() {
    if(this.email !== undefined && this.email !== null && this.phone !== undefined && this.phone !== null) {
      console.log(`${this.name} can be reached at ${this.email} or ${this.phone}`);
    } else {
      console.log(`${this.name} has no contact information available`);
    }
  }
}

const john = new Person('John Doe', 'john.doe@example.com', '(123) 456-7890');
const jane = new Person('Jane Smith', null, '987-654-3210');

john.contact(); // logs 'John Doe can be reached at john.doe@example.com or (123) 456-7890'
jane.contact(); // logs 'Jane Smith has no contact information available'

Explanation: In this code snippet, the Person class has a name property and optional email and phone properties. The contact() function checks if both email and phone are not undefined and not null before logging the details. Otherwise, it logs a message saying that no contact information is available. To initialize the properties with null, the constructor uses the nullish coalescing operator, ??. When creating a new Person, you can pass null or undefined as arguments, and the class will interpret them as null.

Conclusion

Understanding and correctly implementing conditional types like NonNullable<T> in TypeScript is crucial to reduce potential code pitfalls. By reviewing examples of numerical operations and contact information handling, we've seen how this conditional type helps reinforce our code against null or undefined values. This highlights the utility of TypeScript's conditional types not only for enhancing code stability, but also for easing our coding journey. So keep experimenting and finding the best ways to deploy these tools for creating robust, secure, and efficient programs!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co