Skip to main content

NonNullable<Type> Utility Types in TypeScript With Examples

What Is NonNullable<Type>

NonNullable<Type> is a utility type in TypeScript that helps you create a new type by removing null and undefined from an existing type. Essentially NonNullable<Type> makes sure that the values assigned to the new type cannot be null or undefined. This helps you write safer code, ensuring that you won't encounter unexpected errors caused by these values.

Syntax

Here's the basic syntax for using NonNullable<Type>

type NewType = NonNullable<Type>;
  • NonNullable: This is the name of the utility type. It indicates that you want to create a non-nullable version of an existing type.
  • <Type>: The angle brackets < and > are used to specify a type parameter. You replace Type with the actual type you want to make non-nullable.

For example, let's say you have a type called MyType which can be either a string, number, null, or undefined:

type MyType = string | number | null | undefined;

Now, you want to create a new type that removes the null and undefined possibilities. You would use the NonNullable utility type like this:

type MyNonNullType = NonNullable<MyType>;

After applying NonNullable, the new type MyNonNullType will only accept string and number values. It will not allow null or undefined values.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

Example Use Case

Imagine you're developing an eCommerce application, and you have a Product type representing a product in your store. The product can have a discount, which can be either a fixed amount or a percentage. The discount can also be null if there is no discount available.

type Discount = {
type: "fixed" | "percentage" | null;
value: number | null;
};

type Product = {
id: string;
name: string;
price: number;
discount: Discount;
};

Now, let's say you need to create a function that calculates the discounted price of a product, but it should only accept products that have valid discounts. You can use NonNullable<Type> to make sure that the discount type and value are not null.

First, create a new ValidDiscount type that removes the null possibility from the discount type and value:

type ValidDiscount = {
type: NonNullable<Discount["type"]>;
value: NonNullable<Discount["value"]>;
};

Next, create a new ProductWithDiscount type, which is the same as the original Product type, but with the ValidDiscount type for the discount property:

type ProductWithDiscount = Omit<Product, "discount"> & {
discount: ValidDiscount;
};

Finally, define the calculateDiscountedPrice function, which accepts a ProductWithDiscount as an argument:

function calculateDiscountedPrice(product: ProductWithDiscount): number {
const { price, discount } = product;

if (discount.type === "fixed") {
return price - discount.value;
} else if (discount.type === "percentage") {
return price * (1 - discount.value / 100);
}

// This point should never be reached,
// as the discount is guaranteed to be valid.
return price;
}

By using NonNullable<Type>, you ensure that the calculateDiscountedPrice function only accepts products with valid discounts, avoiding errors caused by null values in the discount type or value.

Combining NonNullable<Type> With Other Utility Types

Let's try to combine NonNullable<Type> with the Partial<Type> utility type. Let's consider a User type representing a user profile in a social media application:

type User = {
id: string;
name: string;
email: string;
bio: string | null;
birthDate: Date | null;
};

Now, imagine you want to create a function to update a user's profile, allowing the user to update only some of the fields (name, email, bio, and birthDate). You also want to make sure that after the update, the name and email fields are not null. You can use Partial<Type> and NonNullable<Type> together to achieve this.

First, create a UserUpdate type using Partial<Type> to make all properties optional:

type UserUpdate = Partial<User>;

Next, update the name and email properties to be non-nullable by combining NonNullable<Type> with the mapped type:

type NonNullableUserUpdate = {
[K in keyof UserUpdate]: K extends "name" | "email"
? NonNullable<UserUpdate[K]>
: UserUpdate[K];
};

Now, you can define the updateUserProfile function, which accepts a userId and a NonNullableUserUpdate object, and updates the user's profile accordingly:

function updateUserProfile(
userId: string,
update: NonNullableUserUpdate
): User {
// Fetch the user from the database
// (assuming a `getUserById` function exists)
const user = getUserById(userId);

// Update the user's properties
for (const key in update) {
user[key] = update[key];
}

// Save the updated user back to the
// database (assuming a `saveUser` function exists)
saveUser(user);

return user;
}

By combining NonNullable<Type> with other utility types, you can create more advanced and flexible types, while ensuring type safety and avoiding potential errors caused by null or undefined values.

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.

YouTube @cloudaffle