TypeScript null & undefined: A Comprehensive Tutorial with Code Examples
In TypeScript, null and undefined are important concepts that represent “nothing” or the absence of a value. Understanding how they work, how TypeScript treats them, and how to handle them properly in your code can help prevent common runtime errors.
This tutorial will guide you through the use of null and undefined, along with best practices and examples.
Table of Contents
1. Introduction to null and undefined
In TypeScript (as in JavaScript), null and undefined are two special types used to represent the absence of a value:
undefined: Indicates that a variable has been declared but not assigned a value.
null: Indicates an intentional absence of any object or value.
Example 1: null and undefined in TypeScript
let value1: undefined = undefined; let value2: null = null; console.log(value1); // Output: undefined console.log(value2); // Output: null
2. Differences Between null and undefined
While both null and undefined represent “nothing,” they are not the same:
undefined is the default value assigned to variables that are declared but not initialized.
null is a value that represents the intentional absence of any object value, and it must be explicitly assigned.
Example 2: Differences Between null and undefined
let uninitializedValue: undefined; // Implicitly undefined let nullValue: null = null; // Explicitly null console.log(typeof uninitializedValue); // Output: "undefined" console.log(typeof nullValue); // Output: "object"
The typeof operator treats null as an object due to a quirk in JavaScript, whereas undefined is treated as its own type.
3. TypeScript’s strictNullChecks Option
When the strictNullChecks option is enabled in your TypeScript configuration (tsconfig.json), variables of types like string or number will not allow null or undefined unless explicitly specified. This is a crucial feature for type safety.
Example 3: With strictNullChecks Enabled
let name: string = "John"; // name = null; // Error: Type 'null' is not assignable to type 'string' // name = undefined; // Error: Type 'undefined' is not assignable to type 'string'
If strictNullChecks is disabled, null and undefined can be assigned to any type.
Enabling strictNullChecks:
In tsconfig.json:
{ "compilerOptions": { "strictNullChecks": true } }
4. Handling null and undefined with Union Types
If you want to explicitly allow null or undefined for certain variables, you can use union types to define multiple valid types.
Example 4: Union Types with null and undefined
let username: string | null = null; let age: number | undefined; username = "Alice"; // Valid age = 25; // Valid age = undefined; // Valid // username = 123; // Error: Type 'number' is not assignable to type 'string | null'
In this example, username can be either a string or null, and age can be a number or undefined.
5. Optional Parameters and Default Values
In TypeScript, function parameters can be marked as optional by appending a ?. This means that the parameter can be undefined if no value is provided.
Example 5: Optional Parameters
function greet(name?: string): string { if (name) { return `Hello, ${name}!`; } else { return "Hello!"; } } console.log(greet("John")); // Output: Hello, John! console.log(greet()); // Output: Hello!
You can also provide default values for parameters to avoid dealing with undefined inside the function body.
Example 6: Default Parameter Values
function greetWithDefault(name: string = "Guest"): string { return `Hello, ${name}!`; } console.log(greetWithDefault("John")); // Output: Hello, John! console.log(greetWithDefault()); // Output: Hello, Guest!
6. Nullish Coalescing (??)
The nullish coalescing operator (??) is a feature in TypeScript that returns the right-hand operand if the left-hand operand is null or undefined. It's a great way to provide fallback values.
Example 7: Nullish Coalescing
let userInput: string | null = null; let defaultName = "Anonymous"; let name = userInput ?? defaultName; // "Anonymous" because userInput is null console.log(name); // Output: Anonymous
In this example, ?? ensures that name will be “Anonymous” if userInput is either null or undefined.
7. Safe Access with Optional Chaining (?.)
Optional chaining (?.) is a feature that allows you to safely access deeply nested object properties or methods that might be null or undefined.
Example 8: Optional Chaining
type User = { name: string; address?: { city: string; }; }; let user: User = { name: "Alice", address: undefined }; console.log(user.address?.city); // Output: undefined (safe access)
Without optional chaining, attempting to access user.address.city would throw an error if address is undefined.
8. Best Practices for Dealing with null and undefined
Enable strictNullChecks: Enabling strictNullChecks ensures that you explicitly handle null and undefined and avoid accidental errors.
Use Optional Chaining (?.): Safely access nested properties without worrying about null or undefined.
Default Values with Nullish Coalescing (??): Use ?? to provide fallback values for potentially null or undefined variables.
Avoid Using null When Possible: In many cases, using undefined (the default) is sufficient and less confusing than null.
Use Union Types for Explicit Nullability: If a variable can be null or undefined, use union types like string | null or number | undefined.
Conclusion
Understanding how null and undefined work in TypeScript, along with the tools TypeScript provides to handle them (strictNullChecks, optional chaining, and nullish coalescing), will help you write safer, more robust code.
Whether you’re dealing with optional values or working with deeply nested objects, TypeScript provides mechanisms to ensure that you handle these potential pitfalls effectively.