Check for null and undefined in TypeScript
Learn various methods to check for both null and undefined values in TypeScript with modern syntax and best practices.
How can I check for both null and undefined values in TypeScript?
Since TypeScript is strongly-typed, simply using if () {} to check for both null and undefined doesn’t really feel appropriate, you know? Does TypeScript actually have any dedicated function or syntax sugar for this purpose?
TypeScript provides several elegant ways to check for both null and undefined values, with modern syntax sugar that makes null handling much cleaner. The most straightforward approaches include using the == null comparison operator for combined checks, TypeScript 3.7+'s optional chaining (?.) and nullish coalescing (??) operators, and various type guard patterns for more precise type narrowing.
Contents
- Basic Comparison Methods
- TypeScript 3.7+ Modern Syntax
- Type Guards and Type Narrowing
- Practical Examples and Use Cases
- Best Practices and Recommendations
Basic Comparison Methods
The simplest and most common way to check for both null and undefined in TypeScript is by using the == null comparison. According to Mozilla Developer Network, this works because the == operator performs type coercion and treats null and undefined as equal when compared with each other.
let value: string | null | undefined;
// Check if value is null or undefined
if (value == null) {
console.log("Value is either null or undefined");
}
// Check if value is NOT null or undefined
if (value != null) {
console.log("Value has a valid value (not null or undefined)");
}
Double vs Triple Equals
The difference between == and === matters here, actually:
value == null- checks for bothnullandundefined(type coercion)value === null- only checks fornull(strict comparison)value === undefined- only checks forundefined(strict comparison)
As noted in the TypeScript 2.0 documentation, “Non-null and non-undefined type guards may use the ==, !=, ===, or !== operator to compare to null or undefined, as in x != null or x === undefined. The effects on subject variable types accurately reflect JavaScript semantics.”
TypeScript 3.7+ Modern Syntax
TypeScript 3.7 introduced powerful operators that revolutionize null and undefined handling. Honestly, these features changed how I approach null checks in my daily coding.
Optional Chaining (?.)
The optional chaining operator allows you to safely access properties that might be null or undefined:
interface User {
name: string;
address?: {
street: string;
city?: string;
};
}
const user: User | null = null;
// Without optional chaining - would throw error
const city = user?.address?.city; // Returns undefined instead of throwing
// Safe property access
const streetName = user?.address?.street ?? "Unknown street";
According to MDN documentation, “The optional chaining operator (?.) is useful to access a property of an object which may be null or undefined.”
Nullish Coalescing (??)
The nullish coalescing operator provides a default value only when the expression evaluates to null or undefined:
const config = {
timeout: 0,
retries: null,
maxConnections: undefined
};
// Only uses default if value is null or undefined
const timeout = config.timeout ?? 5000; // Uses 0 (falsy but not nullish)
const retries = config.retries ?? 3; // Uses 3 (retries was null)
const connections = config.maxConnections ?? 10; // Uses 10 (was undefined)
As explained in LogRocket’s TypeScript guide, “The nullish coalescing operator is the ability to fall back to a default value when the primary expression evaluates to null or undefined.”
Combining Both Operators
These operators work beautifully together, by the way:
interface User {
name: string;
preferences?: {
theme: string;
notifications?: {
email: boolean;
push?: boolean;
};
};
}
const user: User | null = getUser();
const theme = user?.preferences?.theme ?? 'dark';
const pushEnabled = user?.preferences?.notifications?.push ?? true;
Type Guards and Type Narrowing
TypeScript provides sophisticated type narrowing capabilities for null and undefined checks. You can get really creative with these.
Explicit Type Guards
function isNotNullOrUndefined<T>(value: T | null | undefined): value is T {
return value != null;
}
const value: string | null | undefined = getValue();
if (isNotNullOrUndefined(value)) {
// TypeScript knows 'value' is string here
console.log(value.toUpperCase());
}
typeof Guards
function processValue(value: string | null | undefined) {
if (typeof value === 'string') {
// TypeScript narrows to string type
return value.length;
}
// TypeScript knows value is null or undefined here
return 0;
}
Custom Type Predicates
type NotNull<T> = T extends null | undefined ? never : T;
function isNotNull<T>(value: T): value is NotNull<T> {
return value != null;
}
const nullableValue: string | null = getValue();
if (isNotNull(nullableValue)) {
// TypeScript knows nullableValue is string here
nullableValue.toUpperCase();
}
Practical Examples and Use Cases
API Response Handling
interface ApiResponse {
data: {
user: {
id: string;
name: string;
email?: string;
};
} | null;
error?: string;
}
function handleApiResponse(response: ApiResponse) {
// Check if response has data
if (response.data?.user) {
const user = response.data.user;
// Safe property access with nullish coalescing
const email = user.email ?? 'No email provided';
console.log(`User: ${user.id}, ${user.name}, ${email}`);
} else {
console.log('No user data available');
}
}
Configuration Object Processing
interface AppConfig {
database: {
host: string;
port: number;
username?: string;
password?: string;
};
logging: {
level: 'debug' | 'info' | 'warn' | 'error';
enabled?: boolean;
};
}
const config: AppConfig | null = loadConfig();
// Process configuration safely
const dbHost = config?.database.host ?? 'localhost';
const dbPort = config?.database.port ?? 5432;
const dbUser = config?.database.username ?? 'default';
const dbPass = config?.database.password ?? '';
const logLevel = config?.logging.level ?? 'info';
const loggingEnabled = config?.logging.enabled ?? true;
Form Validation
interface FormField {
value: string | null | undefined;
errors?: string[];
required: boolean;
}
function validateField(field: FormField): boolean {
// Check if field has value or is not required
if (!field.required || field.value != null) {
// Further validation logic
return true;
}
// Field is required but has no value
return false;
}
Best Practices and Recommendations
When to Use Each Method
-
Use
== nullfor simple checks: Best for straightforward null/undefined checks where you don’t need type narrowing. -
Use
!= nullfor truthy checks: Ideal when you want to ensure a value exists and is not null/undefined. -
Use
?.for safe property access: Perfect for chaining property access when intermediate values might be null/undefined. -
Use
??for default values: Best when you want to provide defaults only for null/undefined, not other falsy values.
Performance Considerations
According to TypeScript documentation, these modern operators are designed to be efficient and compile down to clean JavaScript code. The nullish coalescing operator specifically “treats undefined and null as specific values” rather than treating all falsy values the same way.
TypeScript Configuration Impact
When strictNullChecks is enabled (recommended), TypeScript requires more explicit handling of null and undefined. As noted in W3Schools TypeScript guide, “When strictNullChecks is enabled, TypeScript requires values to be set unless undefined is explicitly added to the type.”
Common Pitfalls to Avoid
-
Don’t use
||for null checks:value || defaultValuewill trigger for falsy values like0,'', andfalse, not just null/undefined. -
Be aware of type widening: Without proper type guards, TypeScript might not narrow types as expected.
-
Consider the context: In some cases, you might want to handle null and undefined differently, even if they’re both “absent” values.
Sources
- Stack Overflow - TypeScript null and undefined checking
- TypeScript 2.0 Documentation - Null and Undefined
- W3Schools - TypeScript Null & Undefined
- MDN - Nullish coalescing operator
- LogRocket - Optional chaining and nullish coalescing in TypeScript
- TypeScript 3.7 Release Notes
- GeeksforGeeks - How to check null and undefined in TypeScript
- Angular Wiki - Checking null or undefined in TypeScript
Conclusion
TypeScript offers several elegant approaches for checking both null and undefined values, each suited to different scenarios. The == null comparison remains the simplest way to check for both values simultaneously, while TypeScript 3.7+'s optional chaining and nullish coalescing operators provide modern, expressive syntax for safe property access and default value handling. For more precise type control, TypeScript’s type guard system allows you to create custom narrowing logic that works seamlessly with the type system.
Key takeaways:
- Use
value == nullfor simple combined null/undefined checks - Leverage
?.for safe nested property access - Use
??for default values that only apply to null/undefined - Implement custom type guards for complex type narrowing scenarios
- Enable
strictNullChecksfor better type safety and more explicit null handling
These modern TypeScript features make null and undefined handling much more intuitive and less error-prone, allowing you to write cleaner, more robust code while maintaining strong type safety. Honestly, once you get used to these patterns, you’ll wonder how you ever coded without them!