Lesson 41 of 60 – Type Guards
68%

Type Guards in TypeScript

Type guards are techniques that help TypeScript determine the specific type of a value at runtime. They are commonly used with union types to safely access properties and methods.

Note: Type guards help TypeScript narrow a value from a broad type to a more specific type.

1. What is a Type Guard?

A type guard is a condition or function that helps TypeScript determine the type of a value.

function show(
    value: string | number
) {

    if (typeof value === "string") {

        console.log(
            value.toUpperCase()
        );

    }

}

The typeof check acts as a type guard.

2. Why Use Type Guards?

Type guards are useful when a value can have multiple types.

function printValue(
    value: string | number
) {

    if (typeof value === "string") {

        console.log(
            value.length
        );

    } else {

        console.log(
            value.toFixed(2)
        );

    }

}

The guard allows each type to be handled safely.

3. typeof Type Guard

The typeof operator is commonly used for primitive types.

function showValue(
    value: string | number
) {

    if (typeof value === "string") {

        console.log("String");

    } else {

        console.log("Number");

    }

}

4. typeof with String

You can check whether a value is a string.

function show(
    value: string | number
) {

    if (typeof value === "string") {

        console.log(
            value.toUpperCase()
        );

    }

}

5. typeof with Number

You can also check whether a value is a number.

function show(
    value: string | number
) {

    if (typeof value === "number") {

        console.log(
            value.toFixed(2)
        );

    }

}

6. typeof with Boolean

function show(
    value: string | boolean
) {

    if (typeof value === "boolean") {

        console.log(
            value
        );

    }

}

The condition narrows value to boolean.

7. instanceof Type Guard

The instanceof operator can be used to check whether an object is an instance of a class.

class Student {
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class Teacher {
    subject: string;

    constructor(subject: string) {
        this.subject = subject;
    }
}

function show(
    person: Student | Teacher
) {

    if (person instanceof Student) {

        console.log(
            person.name
        );

    }

}

8. instanceof with Multiple Classes

function show(
    person: Student | Teacher
) {

    if (person instanceof Student) {

        console.log(
            "Student:",
            person.name
        );

    } else if (
        person instanceof Teacher
    ) {

        console.log(
            "Teacher:",
            person.subject
        );

    }

}

9. in Operator as Type Guard

The in operator checks whether a property exists in an object.

interface Student {
    name: string;
    course: string;
}

interface Teacher {
    name: string;
    subject: string;
}

function show(
    user: Student | Teacher
) {

    if ("course" in user) {

        console.log(
            user.course
        );

    }

}

10. in Operator with Two Object Types

interface Admin {
    name: string;
    permissions: string[];
}

interface Student {
    name: string;
    course: string;
}

function showUser(
    user: Admin | Student
) {

    if ("permissions" in user) {

        console.log(
            user.permissions
        );

    } else {

        console.log(
            user.course
        );

    }

}

11. Equality Type Guard

Equality checks can also narrow a value.

function show(
    value: "admin" | "student"
) {

    if (value === "admin") {

        console.log(
            "Admin User"
        );

    } else {

        console.log(
            "Student User"
        );

    }

}

12. Type Guard with null

A null check can act as a type guard.

function showName(
    name: string | null
) {

    if (name !== null) {

        console.log(
            name.toUpperCase()
        );

    } else {

        console.log(
            "No name"
        );

    }

}

13. Type Guard with undefined

You can check whether a value is undefined.

function showPhone(
    phone: string | undefined
) {

    if (phone !== undefined) {

        console.log(
            phone
        );

    } else {

        console.log(
            "Phone unavailable"
        );

    }

}

14. Array.isArray() Type Guard

Array.isArray() can identify an array value.

function showData(
    value: string | number[]
) {

    if (Array.isArray(value)) {

        console.log(
            value.length
        );

    } else {

        console.log(
            value.toUpperCase()
        );

    }

}

15. Truthiness Type Guard

Truthiness checks can narrow values that may be null or undefined.

function showName(
    name: string | null
) {

    if (name) {

        console.log(
            name.toUpperCase()
        );

    }

}

16. Discriminated Union Type Guard

A common literal property can be used to distinguish between object types.

interface Admin {
    type: "admin";
    name: string;
}

interface Student {
    type: "student";
    name: string;
}

type User =
    Admin | Student;

function showUser(
    user: User
) {

    if (user.type === "admin") {

        console.log(
            "Admin:",
            user.name
        );

    } else {

        console.log(
            "Student:",
            user.name
        );

    }

}

17. What is a Custom Type Guard?

A custom type guard is a function whose return type uses the is keyword.

function isString(
    value: unknown
): value is string {

    return typeof value === "string";

}

The expression value is string tells TypeScript that the function can be used to narrow the value to string.

18. Using a Custom Type Guard

function isString(
    value: unknown
): value is string {

    return typeof value === "string";
}

const value: unknown =
    "Hello";

if (isString(value)) {

    console.log(
        value.toUpperCase()
    );

}

After the condition succeeds, TypeScript treats value as a string.

19. Custom Type Guard for Student

interface Student {
    name: string;
    course: string;
}

interface Teacher {
    name: string;
    subject: string;
}

function isStudent(
    user: Student | Teacher
): user is Student {

    return "course" in user;

}

20. Using the Student Type Guard

function showUser(
    user: Student | Teacher
) {

    if (isStudent(user)) {

        console.log(
            "Course:",
            user.course
        );

    } else {

        console.log(
            "Subject:",
            user.subject
        );

    }

}

The custom function makes the narrowing logic reusable.

21. Type Guard with unknown

Type guards are particularly useful with unknown.

function processValue(
    value: unknown
) {

    if (typeof value === "string") {

        console.log(
            value.toUpperCase()
        );

    } else if (
        typeof value === "number"
    ) {

        console.log(
            value.toFixed(2)
        );

    } else {

        console.log(
            "Unknown value"
        );

    }

}

22. Type Guard for API Response

Type guards can be used to identify different API response structures.

interface SuccessResponse {
    status: "success";
    data: string;
}

interface ErrorResponse {
    status: "error";
    message: string;
}

type ApiResponse =
    SuccessResponse |
    ErrorResponse;

function isSuccess(
    response: ApiResponse
): response is SuccessResponse {

    return response.status === "success";

}

23. Using API Response Type Guard

function handleResponse(
    response: ApiResponse
) {

    if (isSuccess(response)) {

        console.log(
            response.data
        );

    } else {

        console.log(
            response.message
        );

    }

}

The type guard tells TypeScript which response structure is available in each branch.

24. Type Guards in React Props

Type guards can help when a React component receives different types of props.

type ValueProps = {
    value: string | number;
};

function ValueDisplay(
    props: ValueProps
) {

    if (
        typeof props.value === "string"
    ) {

        return (
            <div>
                {props.value.toUpperCase()}
            </div>
        );

    }

    return (
        <div>
            {props.value.toFixed(2)}
        </div>
    );
}

25. Type Guards in React Native

Type guards can also be used when React Native components work with union types.

type Message =
    string | {
        text: string;
    };

function MessageView(
    message: Message
) {

    if (typeof message === "string") {

        return (
            <Text>
                {message}
            </Text>
        );

    }

    return (
        <Text>
            {message.text}
        </Text>
    );
}

26. Common Type Guard Mistake

A common mistake is performing a type-specific operation before checking the type.

function show(
    value: string | number
) {

    // Incorrect:
    // console.log(
    //     value.toUpperCase()
    // );

    if (typeof value === "string") {

        console.log(
            value.toUpperCase()
        );

    }

}

Always perform the appropriate type check before using type-specific methods.

27. When Should You Use Type Guards?

Type guards are useful whenever your code works with multiple possible types.

  • Union types
  • Unknown values
  • API responses
  • Different object structures
  • Class instances
  • Optional values
  • React props
  • React Native data

28. Common Type Guard Techniques

Important type guard techniques include:

  • typeof
  • instanceof
  • in
  • Equality checks
  • Truthiness checks
  • Array.isArray()
  • Discriminated unions
  • Custom type guard functions
  • Null and undefined checks

29. Complete Practical Example

interface Student {
    type: "student";
    name: string;
    course: string;
}

interface Teacher {
    type: "teacher";
    name: string;
    subject: string;
}

type User =
    Student | Teacher;

function isStudent(
    user: User
): user is Student {

    return user.type === "student";

}

function showUser(
    user: User
) {

    console.log(
        "Name:",
        user.name
    );

    if (isStudent(user)) {

        console.log(
            "Course:",
            user.course
        );

    } else {

        console.log(
            "Subject:",
            user.subject
        );

    }

}

showUser({
    type: "student",
    name: "Amit",
    course: "TypeScript"
});

showUser({
    type: "teacher",
    name: "Rahul",
    subject: "JavaScript"
});

30. Type Guards Summary

Type guards help TypeScript determine the exact type of a value during program execution.

function isString(
    value: unknown
): value is string {

    return typeof value === "string";
}

Type guards make code safer by allowing you to perform operations only after TypeScript knows that the value has the required type.

📌 Key Points

  • Type guards help identify a specific type.
  • They are commonly used with union types.
  • typeof is useful for primitive types.
  • instanceof is useful for class instances.
  • The in operator checks for object properties.
  • Equality checks can narrow literal values.
  • Array.isArray() can identify arrays.
  • Null and undefined checks can narrow optional values.
  • Discriminated unions provide effective object type guards.
  • Custom type guards use the value is Type syntax.
  • Type guards are useful with the unknown type.
  • Type guards are useful in React and React Native applications.

🧠 Quick Quiz

Question: Which keyword is used in a custom type guard return type?