Programming

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.

1 answer 1 view

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

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.

typescript
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 both null and undefined (type coercion)
  • value === null - only checks for null (strict comparison)
  • value === undefined - only checks for undefined (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:

typescript
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:

typescript
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:

typescript
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

typescript
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

typescript
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

typescript
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

typescript
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

typescript
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

typescript
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

  1. Use == null for simple checks: Best for straightforward null/undefined checks where you don’t need type narrowing.

  2. Use != null for truthy checks: Ideal when you want to ensure a value exists and is not null/undefined.

  3. Use ?. for safe property access: Perfect for chaining property access when intermediate values might be null/undefined.

  4. 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

  1. Don’t use || for null checks: value || defaultValue will trigger for falsy values like 0, '', and false, not just null/undefined.

  2. Be aware of type widening: Without proper type guards, TypeScript might not narrow types as expected.

  3. Consider the context: In some cases, you might want to handle null and undefined differently, even if they’re both “absent” values.

Sources

  1. Stack Overflow - TypeScript null and undefined checking
  2. TypeScript 2.0 Documentation - Null and Undefined
  3. W3Schools - TypeScript Null & Undefined
  4. MDN - Nullish coalescing operator
  5. LogRocket - Optional chaining and nullish coalescing in TypeScript
  6. TypeScript 3.7 Release Notes
  7. GeeksforGeeks - How to check null and undefined in TypeScript
  8. 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 == null for 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 strictNullChecks for 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!

Authors
Verified by moderation
Moderation
Check for null and undefined in TypeScript