Skip to main content

What is a type guard function?

What a Type Guard Function is

A type guard function is a special function that returns a boolean and tells TypeScript that if it returned true, then its argument has a specific type.

Syntax:

javascript
function isSomething(value: unknown): value is SomeType { // check logic }

The key part is the return type: value is SomeType -> a type predicate.


Example 1. A basic custom type guard

javascript
function isString(value: unknown): value is string { return typeof value === "string"; } function print(value: unknown) { if (isString(value)) { // here value: string console.log(value.toUpperCase()); } else { // value is not a string console.log("Not a string"); } }

Thanks to value is string, TypeScript understands that inside if (isString(value)) the variable's type has narrowed to string.


Why Type Guard Functions are needed

  1. To extend TypeScript's type system - teaching it to understand your checks.
  2. To avoid forced casts (as).
  3. To safely work with unknown, any, or union types.
  4. To narrow types inside logical conditions, filters, and higher-order functions.

Example 2. Checking an array

javascript
function isArray(value: unknown): value is any[] { return Array.isArray(value); } function process(value: unknown) { if (isArray(value)) { // value: any[] console.log(value.length); } else { console.log("Not an array"); } }

How this works under the hood

A regular function returns boolean:

javascript
function check(value: unknown): boolean

TypeScript cannot infer a type from this. But a function with a type predicate (value is Type) tells the compiler:

"If I returned true, treat the variable as now having type Type".


Example 3. With a union type

javascript
type Dog = { kind: "dog"; bark: () => void }; type Cat = { kind: "cat"; meow: () => void }; function isDog(animal: Dog | Cat): animal is Dog { return animal.kind === "dog"; } function makeSound(animal: Dog | Cat) { if (isDog(animal)) { animal.bark(); // animal: Dog } else { animal.meow(); // animal: Cat } }

This is a typical example of type guard + narrowing: the isDog function narrows the union type Dog | Cat to a specific subtype.


Where it's often used

ScenarioExample
Checking an argument's typeisString(x)
Checking for null/undefinedisNonNull(x)
Checking a discriminantisError(response)
An instanceof checkisDate(obj)
Filtering an arrayarr.filter(isString)

Example 4. Filtering an array with a Type Guard

javascript
function isString(value: unknown): value is string { return typeof value === "string"; } const mixed = [1, "a", 2, "b", true]; const strings = mixed.filter(isString); // strings: string[]

TypeScript knows that only strings remain after the filter.


Example 5. Checking complex structures

javascript
type User = { id: number; name: string }; function isUser(obj: any): obj is User { return ( typeof obj === "object" && obj !== null && typeof obj.id === "number" && typeof obj.name === "string" ); } const data: unknown = JSON.parse('{"id":1,"name":"Tom"}'); if (isUser(data)) { // data: User console.log(data.name.toUpperCase()); }

Without a type guard you would have had to write:

javascript
const user = data as User; // unsafe, may fail at runtime

Example 6. Checking whether a key exists

javascript
function hasProperty<T extends object, K extends PropertyKey>( obj: T, key: K ): obj is T & Record<K, unknown> { return key in obj; } const person = { name: "Alex" }; if (hasProperty(person, "name")) { // person: { name: string } & Record<"name", unknown> console.log(person.name); }

Example 7. Composing several type guards

javascript
function isDefined<T>(value: T | undefined | null): value is T { return value != null; } function isPositive(n: number): boolean { return n > 0; } const arr = [1, null, 2, undefined, -5, 3]; const positive = arr.filter(isDefined).filter(isPositive); // positive: number[]

After isDefined, TypeScript knows that the array no longer contains null or undefined.


The difference between a Type Guard Function and a regular function

Regular functionType Guard Function
Returns booleanReturns value is Type
Does not change the variable's typeNarrows the variable's type
Does not affect the compilerChanges how TS perceives the type
Used as a logical checkUsed as proof of type

Example: how TS "thinks"

javascript
if (isUser(obj)) { // TypeScript "believed" the isUser check // obj: User } else { // obj: unknown }

TypeScript does not execute the function, it simply trusts the value is Type annotation - this is the developer's promise that the function's logic is indeed correct.


Important notes

  1. TypeScript does not verify that the check inside is correct - that is the developer's responsibility.
javascript
function isNumber(x: any): x is number { return typeof x === "string"; // TS will believe this, even though it's wrong }
  1. Type guards work only with a function parameter, not with arbitrary variables.
  2. Generics can be used to build universal guards.

Summary

TermDefinition
Type Guard FunctionA function that returns value is Type and tells TS that the value has the specified type
PurposeNarrowing types and safely working with unknown, any, and union types
Main featureAffects type analysis, not just execution logic
Typical syntaxfunction isUser(obj: any): obj is User { ... }
Main advantageSafety, autocomplete, and no as

Just remember:

A Type Guard Function is a "guard" that tells TypeScript: "I checked it, you can trust me - this is exactly this type".

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.