- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
Nullable Types in TypeScript
In the world of JavaScript, null and undefined are frequent causes of the dreaded "Uncaught TypeError: Cannot read property of null" runtime errors. TypeScript solves this by introducing Nullable Types. These allow you to explicitly define when a variable is allowed to be empty, forcing you to handle those cases before your code even runs.
Key Concepts of Nullable Types
- Union Types: We create nullable types using the pipe symbol (
|), which creates a Union Type (e.g.,string | null). - Explicit Intent: Unlike plain JavaScript, where any variable can technically be null, TypeScript requires you to be intentional about which variables can hold "empty" values.
- Safety: By using nullable types, the TypeScript compiler can track where a value might be missing and alert you if you forget to check for it.
strictNullChecks in your tsconfig.json. This is the industry standard and ensures that types are not nullable by default.
Example Usage of Nullable Types
Example 1: Using null and undefined
In real-world applications, you might fetch a user from a database. If the user doesn't exist, the result might be null.
let loggedInUser: string | null = null;
let sessionTimeout: number | undefined = undefined;
// Later in the app logic
loggedInUser = "Alice"; // valid
sessionTimeout = 3600; // valid
Here:
- The
loggedInUservariable can either hold a name or be explicitly set tonullif no one is logged in. - The
sessionTimeoutvariable usesundefinedto indicate that a value hasn't been determined yet.
null and undefined. While they both represent "nothing," null is usually an intentional absence of a value (like an empty database field), whereas undefined means a variable has not been initialized.
Example 2: Declaring Nullable Variables
let profilePictureUrl: string | null = "https://example.com/user.jpg";
// If the user deletes their photo:
profilePictureUrl = null; // perfectly valid TypeScript
In this example:
- By allowing
null, the developer acknowledges that a user might not have a profile picture. If we tried to assignnullto a plainstringtype, TypeScript would throw a compiler error.
Nullable Types in Function Parameters
Nullable types are incredibly useful when writing functions where some data might be missing, such as search filters or user inputs.
function formatMessage(name: string | null): string {
if (name === null) {
return "Welcome, Guest!";
}
return `Welcome back, ${name}!`;
}
console.log(formatMessage("Sarah")); // Output: Welcome back, Sarah!
console.log(formatMessage(null)); // Output: Welcome, Guest!
??) to provide a default value quickly: return `Hello, ${name ?? "Guest"}!`;
Nullable Types with Arrays
Sometimes you have a list where specific items might be missing. This is common when processing data from external APIs where some records are incomplete.
let scores: (number | null)[] = [95, 82, null, 74];
scores.forEach(score => {
// We must check if score is not null before performing math
if (score !== null) {
console.log(`Doubled score: ${score * 2}`);
} else {
console.log("Score missing, skipping...");
}
});
(number | null)[] versus number[] | null. The first is an array that can contain numbers or nulls. The second is either an entire array of numbers OR the entire variable is null.
Using undefined for Optional Parameters
While you can use | undefined, TypeScript provides a shorthand syntax using the ? symbol for optional parameters, which automatically includes undefined.
function logStatus(code: number, message?: string): void {
// 'message' is implicitly 'string | undefined'
if (message === undefined) {
console.log(`Status code: ${code}`);
} else {
console.log(`Status code: ${code} - ${message}`);
}
}
logStatus(404); // Output: Status code: 404
logStatus(200, "All good"); // Output: Status code: 200 - All good
Nullable Types with null vs undefined
While TypeScript allows you to use both, they serve different semantic purposes in a codebase.
null: Use this when you want to explicitly say "This value is empty." It is a value that represents "nothing."undefined: Use this when a value is not yet assigned, or when a function parameter is optional.
let apiResponse: string | null = null; // I've checked the API, and there is no string.
let futureValue: string | undefined; // I haven't checked the API yet.
Using the strictNullChecks Flag
The strictNullChecks flag is the most important configuration for type safety in TypeScript. It is found in your tsconfig.json file.
{
"compilerOptions": {
"strictNullChecks": true
}
}
With strictNullChecks enabled:
- Variables are non-nullable by default.
- A
stringvariable can *only* hold a string. - To allow
null, you must use the union typestring | null.
strictNullChecks makes TypeScript much less effective, as it won't warn you about potential "null pointer" style errors. Keep it on for all modern projects!
Nullable Types with Type Guards
TypeScript is smart. If you check if a variable is null inside an if statement, TypeScript "narrows" the type inside that block. This process is called Type Guarding.
function getLength(input: string | null): void {
// At this point, input could be null. TypeScript won't let us use input.length.
if (input !== null) {
// Inside this block, TypeScript knows input MUST be a string.
console.log(`The length is: ${input.length}`);
} else {
console.log("Input was null, cannot get length.");
}
}
if (input === null) return;
Summary
- Nullable Types: These utilize Union Types (e.g.,
type | null) to allow variables to represent missing data safely. nullvsundefined:nullis usually an intentional "empty" value, whileundefinedis the default state of uninitialized variables.- Type Guards: Use
ifchecks to "narrow" types, allowing you to safely access properties once you've confirmed a value isn'tnull. strictNullChecks: This essential compiler setting forces you to handle nullability, preventing many common production bugs.