Custom type guard functions in Typescript - Time & Space Complexity
We want to understand how the time it takes to check types grows as we use custom type guard functions.
How does the number of checks change when the input size changes?
Analyze the time complexity of the following code snippet.
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string');
}
const data = ['apple', 'banana', 'cherry'];
const result = isStringArray(data);
This code checks if a value is an array of strings by testing each item.
- Primary operation: The
everymethod loops through each item in the array. - How many times: It runs once for each element in the input array.
As the array gets bigger, the number of checks grows in a straight line.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 type checks |
| 100 | 100 type checks |
| 1000 | 1000 type checks |
Pattern observation: The time grows directly with the number of items.
Time Complexity: O(n)
This means the time to check grows in direct proportion to the number of items in the array.
[X] Wrong: "The type guard runs in constant time no matter the array size."
[OK] Correct: Because it checks each item one by one, the time grows as the array grows.
Understanding how type guards scale helps you write efficient checks and shows you think about performance in real code.
What if the type guard also checked nested arrays inside the main array? How would the time complexity change?
Practice
Solution
Step 1: Understand what a type guard does
A type guard checks if a value is of a certain type at runtime.Step 2: Recognize the benefit in TypeScript
It helps TypeScript narrow the type, making code safer and clearer.Final Answer:
To check if a value matches a specific type and help TypeScript narrow types -> Option CQuick Check:
Type guard = check type + narrow [OK]
- Thinking type guards convert types
- Confusing type guards with error handling
- Believing type guards declare new types
isString that checks if a value is a string?Solution
Step 1: Identify the return type for a type guard
A custom type guard returns a type predicate likevalue is string.Step 2: Check the function body
The function should returntrueiftypeof value === 'string'.Final Answer:
function isString(value: any): value is string { return typeof value === 'string'; } -> Option AQuick Check:
Type guard syntax = value is Type [OK]
- Using boolean instead of type predicate as return type
- Returning wrong type predicate
- Returning the type instead of a boolean
function isNumber(value: any): value is number {
return typeof value === 'number';
}
const input: any = 42;
if (isNumber(input)) {
console.log(input.toFixed(2));
} else {
console.log('Not a number');
}Solution
Step 1: Check the type guard function behavior
The functionisNumberreturns true ifvalueis a number.Step 2: Analyze the if condition and output
Sinceinputis 42 (a number), the if block runs andinput.toFixed(2)outputs '42.00'.Final Answer:
42.00 -> Option AQuick Check:
isNumber(42) = true, so prints 42.00 [OK]
- Assuming input is not a number
- Expecting runtime error on toFixed
- Confusing output with string conversion
function isArray(value: any): value is Array {
return Array.isArray(value);
}Solution
Step 1: Understand the return type syntax
The return type should be a type predicate with a specific type, e.g.,value is any[]for arrays.Step 2: Identify the incorrect type usage
Arrayalone is a constructor, not a type for arrays. Useany[]or a typed array instead.Final Answer:
Change return type to 'value is any[]' instead of 'value is Array' -> Option BQuick Check:
Array type predicate = value is any[] [OK]
- Using 'Array' instead of 'any[]' or typed array
- Changing function name unnecessarily
- Using typeof 'array' which is invalid
Dog using a custom type guard?interface Dog { bark(): void; }
interface Cat { meow(): void; }
type Pet = Dog | Cat;
function isDog(pet: Pet): pet is Dog {
// Which implementation is correct?
}Solution
Step 1: Understand the interfaces and type guard goal
We want to check ifpethas abarkmethod to confirm it's aDog.Step 2: Evaluate the implementations
Directly accessingpet.barkorpet.meowcauses TypeScript compile errors because those properties do not exist on the union typePet.pet instanceof Dogdoes not work becauseDogis an interface, not a class with a constructor.
Using(pet as Dog).bark !== undefinedcompiles due to the type assertion and performs a runtime check to see if thebarkproperty exists.Final Answer:
return (pet as Dog).bark !== undefined; -> Option DQuick Check:
Type assertion enables property check in union type guards [OK]
- Using instanceof with interfaces
- Directly accessing properties on union types
- Checking absence of other type's method
Ready to prove it?
Pass the test and this pattern moves unknown
