TypeScript Null & Undefined
TypeScript has a strong system for working with values that may be null or undefined.
Note: By default this checking is turned off. Turn it on by setting strictNullChecks to true in your compiler options. The rest of this page assumes strictNullChecks is enabled.
Types
null and undefined are primitive types. You can use them in type annotations just like string or number, for example inside a union.
Note: With strictNullChecks on, TypeScript expects every value to be set unless undefined is explicitly part of its type.
Example
The variable accepts a string, undefined, or null, so all three assignments are allowed.
null and undefined used as members of a union type.
Declare value with the type string | undefined | null, initialise it to null, then reassign it to 'hello' and then to undefined. The file only assigns; it prints nothing.
Output: TypeScript file and captured output
let value: string | undefined | null = null;
value = 'hello';
value = undefined;
Optional Chaining
Optional chaining is a JavaScript feature that fits well with TypeScript's null handling.
It lets you read a property from an object that may or may not exist, with very short syntax.
Use the ?. operator when accessing the property. If the object before ?. is null or undefined, the whole expression becomes undefined instead of throwing an error.
Example
house.yard?.sqft is undefined when the house has no yard, so the function prints No yard.
?. on an optional nested property.
Declare a House interface with sqft: number and an optional yard object that has its own sqft: number. Write printYardSize(house: House) that reads house.yard?.sqft, logs 'No yard' when the result is undefined and otherwise logs Yard is <size> sqft. Create home with sqft 500 and no yard, and call the function so it prints 'No yard'.
Output: TypeScript file and captured output
interface House {
sqft: number;
yard?: {
sqft: number;
};
}
function printYardSize(house: House) {
const yardSize = house.yard?.sqft;
if (yardSize === undefined) {
console.log('No yard');
} else {
console.log(`Yard is ${yardSize} sqft`);
}
}
let home: House = {
sqft: 500
};
printYardSize(home); // Prints 'No yard'
Nullish Coalescing
Nullish coalescing is another JavaScript feature that works well with TypeScript's null handling.
It lets you give an expression a fallback value that is used only when the value is null or undefined.
This is useful when other falsy values, such as 0 or an empty string, can occur and are still valid.
Use the ?? operator in an expression, in a similar way to the && operator.
Example
mileage ?? 'Not Available' falls back for null, but keeps 0 because 0 is not nullish.
?? as a fallback for null and undefined only.
Write printMileage(mileage: number | null | undefined) that logs Mileage: followed by mileage ?? 'Not Available'. Call it with null (prints 'Mileage: Not Available') and with 0 (prints 'Mileage: 0').
Output: TypeScript file and captured output
function printMileage(mileage: number | null | undefined) {
console.log(`Mileage: ${mileage ?? 'Not Available'}`);
}
printMileage(null); // Prints 'Mileage: Not Available'
printMileage(0); // Prints 'Mileage: 0'
Null Assertion
TypeScript's inference is not perfect. Sometimes you know a value cannot be null or undefined even though its type says it might be.
You could use a cast, but TypeScript also gives you the ! operator as a short way to say "this value is definitely set".
Note: Like a cast, this can be unsafe. Use it with care.
Example
getValue() returns string | undefined. Writing value!.length tells TypeScript to treat value as a string.
!.
Write getValue() with return type string | undefined that returns 'hello', store the result in value, and log 'value length: ' plus value!.length so the output shows the length 5.
Output: TypeScript file and captured output
function getValue(): string | undefined {
return 'hello';
}
let value = getValue();
console.log('value length: ' + value!.length);
Array Bounds Handling
Even with strictNullChecks on, TypeScript assumes by default that reading an array element never gives undefined (unless undefined is part of the array's element type).
The compiler option noUncheckedIndexedAccess changes this. With it on, every index read gets undefined added to its type.
Example
By default array[0] has the type number. With noUncheckedIndexedAccess it becomes number | undefined.
noUncheckedIndexedAccess would change it.
Declare array as number[] holding 1, 2 and 3, then read array[0] into value with a comment noting that under noUncheckedIndexedAccess the type would be number | undefined. Nothing is printed.
Output: TypeScript file and captured output
let array: number[] = [1, 2, 3];
let value = array[0]; // with `noUncheckedIndexedAccess` this has the type `number | undefined`