Error Handling and Type Guards in TypeScript Quiz Quiz

Explore key skills in TypeScript error handling practices and type guard techniques. This quiz covers practical scenarios, custom guards, and best practices for reliable type safety and robust code management.

  1. Type Narrowing Using typeof

    Given the variable 'value' of type unknown, which TypeScript construct correctly narrows it to a string before calling value.toUpperCase()?

    1. if (value instanceof String) { value.toUpperCase(); }
    2. if (value.typeof === 'string') { value.toUpperCase(); }
    3. if (typeof value == 'String') { value.toUpperCase(); }
    4. if (typeof value === 'string') { value.toUpperCase(); }

    Explanation: The first option uses the correct syntax for narrowing unknown to string with typeof, ensuring safe use of string methods. The second option misuses the typeof syntax. The third uses incorrect case ('String' instead of 'string') which will never match. The fourth checks for String objects, which is less appropriate as it does not handle string primitives.

  2. Catching and Handling Errors

    When using a try-catch block in TypeScript, what is the recommended way to handle the caught error for maximum type safety?

    1. Access error.code only since code must exist on all errors.
    2. Check the type of the error with a type guard before accessing its properties.
    3. Always assume error is of type Error and access error.message directly.
    4. Suppress type errors using any for the error variable.

    Explanation: Using a type guard before accessing error properties is recommended, as the error type is unknown by default. Assuming error is always an Error can cause runtime problems if it is a string or another type. Accessing error.code directly is unsafe because not all errors have a code property. Using any disables type safety and should be avoided for robust TypeScript code.

  3. User-Defined Type Guards

    How do you define a custom type guard function in TypeScript to check if an object is of type Person?

    1. function isPerson(obj: Person): boolean { return !!obj.name; }
    2. function isPerson(obj: any): boolean { return typeof obj.name === 'string'; }
    3. function isPerson(obj: any): Person { return obj.name as Person; }
    4. function isPerson(obj: any): obj is Person { return typeof obj.name === 'string'; }

    Explanation: The first option declares the correct signature for a custom type guard using 'obj is Person' as the return type annotation. The second returns a boolean but does not inform TypeScript of type narrowing. The third incorrectly claims to return a Person type directly, which isn't safe. The fourth restricts input to Person, defeating the purpose of the guard.

  4. Handling Optional Properties in Type Guards

    Which approach ensures type safety when using a type guard to check for an optional property, such as 'id' in an object?

    1. Test only that the object is not null before accessing 'id'.
    2. Use a forced type conversion to tell TypeScript the property exists.
    3. Assume 'id' exists and access it directly without checking.
    4. Check if 'id' exists on the object and also check its type within the guard.

    Explanation: By checking that 'id' exists and verifying its type, you avoid runtime errors and ensure only valid values are used. Assuming 'id' exists may throw errors with undefined or null values. Checking only the object for null does not address the property itself. Forced type conversions bypass TypeScript's safety mechanisms, leading to possible bugs.

  5. Discriminated Unions and Type Guards

    For a discriminated union type, such as Shape = { kind: 'circle', radius: number } | { kind: 'square', size: number }, what is a safe way to access 'radius'?

    1. Check if shape.kind === 'circle' before accessing shape.radius.
    2. Use shape['radius'] without validating the kind property.
    3. Check if typeof shape === 'circle' before reading radius.
    4. Access shape.radius directly without checks.

    Explanation: Discriminated unions enable safe property access by checking the discriminant, in this case 'kind'. Accessing radius directly could cause a runtime error if shape is a square. Checking typeof for 'circle' is not valid syntax. Using shape['radius'] without verifying the kind may yield undefined.