TypeScript Nullable Types

In TypeScript, null and undefined are distinct values with specific meanings. null means a value was intentionally set to empty. undefined means a variable was declared but never given a value. TypeScript treats both as types and lets developers control when a variable can or cannot hold these values.

null vs undefined — The Difference

REAL-WORLD ANALOGY

  null      →  An empty plate placed at the table on purpose
              (the chef decided to serve nothing)

  undefined →  No plate at the table at all
              (no one set the table for this seat)
let orderStatus: string | null = null;   // intentionally no status yet
let deliveryDate: string | undefined;    // never set — undefined by default

console.log(orderStatus);   // null
console.log(deliveryDate);  // undefined

strictNullChecks

The strictNullChecks option in tsconfig.json is the switch that makes TypeScript enforce null safety. With it off, any variable can accidentally hold null or undefined. With it on, the compiler catches these mistakes before the code runs.

// tsconfig.json
{
    "compilerOptions": {
        "strictNullChecks": true   // recommended: always true
    }
}

// With strictNullChecks ON:
let name: string = null;   // Error: null is not assignable to type 'string'

// To allow null, declare it explicitly:
let name: string | null = null;  // OK

Combining null and undefined with Types

// Three ways to allow nullable values
let a: string | null       = null;       // only null allowed
let b: string | undefined  = undefined;  // only undefined allowed
let c: string | null | undefined = null; // both allowed

function findUser(id: number): { name: string } | null {
    if (id === 1) {
        return { name: "Kavitha" };
    }
    return null;  // user not found
}

let user = findUser(5);
// user could be { name: string } or null
// TypeScript will not let us use user.name without checking first

Checking Before Using Nullable Values

FLOW DIAGRAM
─────────────────────────────────────────────
let user = findUser(id);
      │
      ├── null?  → "User not found" (handle gracefully)
      │
      └── object? → use user.name (safe to access)
─────────────────────────────────────────────

// Code version
let user = findUser(5);

if (user !== null) {
    console.log(user.name);   // TypeScript: safe here
} else {
    console.log("User not found");
}

Optional Function Parameters

A question mark after a parameter name makes it optional. Optional parameters are automatically type | undefined.

function greet(name: string, title?: string): string {
    if (title !== undefined) {
        return `Hello, ${title} ${name}!`;
    }
    return `Hello, ${name}!`;
}

console.log(greet("Rohan"));           // Hello, Rohan!
console.log(greet("Sharma", "Dr."));   // Hello, Dr. Sharma!

Optional Object Properties

interface BookingForm {
    passengerName: string;
    flightNumber: string;
    mealPreference?: string;    // optional — may not be provided
    specialAssistance?: string; // optional
}

let booking: BookingForm = {
    passengerName: "Meena",
    flightNumber: "AI-202"
    // mealPreference and specialAssistance are fine to omit
};

// Check before using optional property
if (booking.mealPreference !== undefined) {
    console.log(`Meal: ${booking.mealPreference}`);
}

Default Values for undefined

function createLabel(text: string, fontSize?: number): string {
    // If fontSize was not provided, default to 14
    let size = fontSize ?? 14;
    return `<span style="font-size:${size}px">${text}</span>`;
}

console.log(createLabel("Hello"));       // font-size: 14px
console.log(createLabel("Title", 24));   // font-size: 24px

The ?? (Nullish Coalescing) Operator

The ?? operator returns the right side only when the left side is null or undefined. Unlike ||, it does not treat 0 or empty string as falsy.

COMPARISON: || vs ??
─────────────────────────────────────────────────────
let score: number | null = 0;

console.log(score || 10);   // 10 — wrong! 0 is falsy, so || replaces it
console.log(score ?? 10);   // 0  — correct! 0 is not null/undefined

let username: string | null = null;
console.log(username ?? "Guest");  // Guest — null triggers ??
─────────────────────────────────────────────────────

Practical Example: Student Record System

interface Student {
    id: number;
    name: string;
    email: string;
    phone?: string;              // optional
    parentContact: string | null; // may not have parent contact
}

function displayContact(student: Student): void {
    console.log(`Name: ${student.name}`);
    console.log(`Email: ${student.email}`);
    console.log(`Phone: ${student.phone ?? "Not provided"}`);

    if (student.parentContact !== null) {
        console.log(`Parent: ${student.parentContact}`);
    } else {
        console.log("Parent contact: Not available");
    }
}

let s1: Student = {
    id: 1,
    name: "Deepak",
    email: "deepak@school.com",
    phone: "9876543210",
    parentContact: "9123456789"
};

let s2: Student = {
    id: 2,
    name: "Fatima",
    email: "fatima@school.com",
    parentContact: null
};

displayContact(s1);
// Name: Deepak
// Email: deepak@school.com
// Phone: 9876543210
// Parent: 9123456789

displayContact(s2);
// Name: Fatima
// Email: fatima@school.com
// Phone: Not provided
// Parent contact: Not available

Common Nullable Type Patterns

PatternCodeMeaning
Nullable variablelet x: string | nullCan be a string or null
Optional propertyage?: numberCan be number or undefined
Optional parameterfn(x?: string)Caller can skip this argument
Nullish coalescingval ?? "default"Use val unless it is null/undefined
Null checkif (x !== null)Narrows type to remove null

Leave a Comment

Your email address will not be published. Required fields are marked *