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 replaceType
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.
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 DETAILSExample 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.