Summary: In this tutorial, you will learn about the TypeScript null type and how to use the null type with union types.
Introduction to the TypeScript null type #
In TypeScript, null is a type that has a single value, which is also null. The null value represents the intentional absence of any object value.
For example:
let message: null = null;
In this example, the type of the message variable is null; therefore, it can accept only a null value.
If you assign another value to a variable of the null type, you’ll get an error. For example:
let message: null = null;
message= "hello";
Error:
Type '"hello"' is not assignable to type 'null'.
In practice, a variable with the null type is not useful. Instead, you use the null type with another type to represent a value that may be missing.
Using null with union types #
The following example uses the null type with the string type using a union type:
let message: string | null;
message= "hello";
In this example, string | null allows the message to accept either a string or null value.
Narrowing a nullable value #
You can compare a nullable value with null to narrow its type.
For example:
const product = findProduct(1);
if (product !== null) {
console.log(product.toUpperCase());
}
How it works:
First, product has the type string | null.
Second, the condition product !== null removes null from the type inside the if block.
Finally, TypeScript treats product as a string inside the block, so calling toUpperCase() is safe.
You can also handle both cases explicitly:
const product = findProduct(2);
if (product === null) {
console.log("Product not found");
} else {
console.log(product.toUpperCase());
}
Inside the first branch, product is null.
Inside the else branch, product is a string.
TypeScript uses control flow checks such as if statements to narrow union types to more specific types.
Using a truthiness check #
You can also use a truthiness check to exclude null:
function printName(name: string | null): void {
if (name) {
console.log(name.toUpperCase());
}
}
Inside the if block, TypeScript treats name as a string.
However, a truthiness check also excludes other falsy values, such as the empty string.
For example:
printName("");
The function does not print anything because the empty string is falsy, even though it is a valid string.
If an empty string and null have different meanings in your program, use an explicit null check:
function printName(name: string | null): void {
if (name !== null) {
console.log(name.toUpperCase());
}
}
Use an explicit comparison when you only want to exclude null.
Returning null from a function #
A function can return null when it does not have a meaningful result.
For example:
type User = {
id: number;
name: string;
};
const users: User[] = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
function findUser(id: number): User | null {
const user = users.find(user => user.id === id);
return user ?? null;
}
The find() method returns a User when it finds a matching element and undefined otherwise.
The nullish coalescing operator converts the undefined result to null:
return user ?? null;
Therefore, the function has the return type User | null.
You need to narrow the result before accessing its properties:
const user = findUser(1);
if (user !== null) {
console.log(user.name);
}
The function signature clearly tells calling code that a user may not be found.
null vs. undefined #
Both null and undefined can represent missing values, but they are different values and different types.
The null value commonly represents an intentional absence:
let selectedUser: User | null = null;
In this example, null indicates that no user is currently selected.
The undefined value commonly indicates that a value has not been assigned or that an optional property is missing:
type Settings = {
theme?: string;
};
The theme property has the type string | undefined when strictNullChecks is enabled.
A type that accepts both values can include both explicitly:
let value: string | null | undefined;
You can check for each value separately:
if (value === null) {
console.log("The value is intentionally empty");
} else if (value === undefined) {
console.log("The value is not defined");
} else {
console.log(value.toUpperCase());
}
Use null and undefined consistently according to the conventions of your application or API.
Checking for null and undefined together #
The expression value == null checks for both null and undefined because loose equality treats them as equal to each other.
For example:
function printValue(
value: string | null | undefined
): void {
if (value == null) {
console.log("No value");
return;
}
console.log(value.toUpperCase());
}
After the null check, TypeScript narrows value to string.
If you prefer strict equality, check both values explicitly:
if (value === null || value === undefined) {
console.log("No value");
return;
}
Both approaches remove null and undefined from the type after the check.
The nullish coalescing operator #
The nullish coalescing operator ?? provides a fallback when a value is null or undefined.
For example:
function getDisplayName(name: string | null): string {
return name ?? "Guest";
}
If name contains a string, the function returns that string.
If name is null, the function returns "Guest".
console.log(getDisplayName("Alice"));
console.log(getDisplayName(null));
Output:
Alice
Guest
The ?? operator differs from the logical OR operator || because it only uses the fallback for null or undefined.
Consider the following example:
const value = "";
const usingOr = value || "Default";
const usingNullish = value ?? "Default";
The usingOr variable contains "Default" because an empty string is falsy.
The usingNullish variable contains an empty string because the value is neither null nor undefined.
Use ?? when valid falsy values such as "", 0, or false should be preserved.
Optional chaining with nullable values #
The optional chaining operator ?. allows you to access a property or call a method only when the value is not null or undefined.
For example:
type Customer = {
name: string;
};
function printCustomer(customer: Customer | null): void {
console.log(customer?.name);
}
If customer contains an object, the expression returns its name property.
If customer is null, the expression returns undefined instead of accessing the property.
You can combine optional chaining with nullish coalescing:
function getCustomerName(
customer: Customer | null
): string {
return customer?.name ?? "Unknown customer";
}
How it works:
First, customer?.name returns the name when customer is not null.
Second, it returns undefined when customer is null.
Finally, ?? replaces undefined with "Unknown customer".
The non-null assertion operator #
The non-null assertion operator ! tells TypeScript that a value is not null or undefined.
For example:
function getLength(value: string | null): number {
return value!.length;
}
The ! operator removes null from the type without adding a runtime check.
However, the following call causes a runtime error:
getLength(null);
TypeScript accepts the code, but JavaScript attempts to access length on null.
Therefore, use the non-null assertion operator only when you have information that the compiler cannot determine.
In most cases, an explicit check is safer:
function getLength(value: string | null): number {
if (value === null) {
return 0;
}
return value.length;
}
The explicit check handles the nullable case at runtime and allows TypeScript to narrow the type safely.
Nullable object properties #
An object property can explicitly allow null.
For example:
type Employee = {
id: number;
name: string;
manager: string | null;
};
The manager property must contain either a string or null:
const employee: Employee = {
id: 1,
name: "Alice",
manager: null
};
This is different from an optional property:
type Employee = {
id: number;
name: string;
manager?: string;
};
A nullable property is present but may contain null.
An optional property may be absent and therefore may produce undefined when accessed.
Choose the form that matches the data model:
manager: string | null;
Use this form when the property must exist but may intentionally have no value.
manager?: string;
Use this form when the property itself may be omitted.
Summary #
- The
nulltype contains only thenullvalue. - Use a union such as
string | nullwhen a value may be missing. - Check a nullable value before accessing its properties or methods.
- Use
value !== nullwhen you only need to excludenull. - Use
value == nullor an explicit combined check to exclude bothnullandundefined. - Use
??to provide a fallback fornullorundefinedwhile preserving other falsy values. - Use
?.to access properties safely on nullable values. - Use nullable properties when a property must exist but may intentionally contain no value.
Quiz #
TypeScript null Type
Thank you for your feedback!