← Back to TypeScript Course | Chapter 8: Advanced Types | Lesson 4 of 20

Custom Type Guards

A custom type guard is a function that tells TypeScript whether a value has a particular type. A predicate return type such as value is User lets TypeScript narrow the value after the guard succeeds.
Syntax
typescript
function isType(value: unknown): value is TargetType {
  return /* boolean check */;
}

Basic Type Predicate

A type predicate uses the form parameterName is Type as its return type annotation — the function body should return a boolean that genuinely and accurately checks whether the value matches that type.

Example: Basic Type Predicate

typescript
function isString(value: unknown): value is string {
  return typeof value === "string";
}
const val: unknown = "hello";
if (isString(val)) console.log(val.toUpperCase());

Checking Object Shapes

Custom guards earn their keep most when working with unknown objects from external sources like API responses — check that every required property actually exists and has the right type before claiming the value matches an interface.

Example: Checking Object Shapes

typescript
interface User {
  id: number;
  name: string;
}
function isUser(value: any): value is User {
  return typeof value?.id === "number" && typeof value?.name === "string";
}
const data: any = { id: 1, name: "Ravi" };
if (isUser(data)) console.log(data.name);

Guards for Union Types

A custom guard can distinguish between the members of a union type, which matters whenever different variants in that union carry different properties that plain equality checks can't tell apart.

Example: Guards for Union Types

typescript
type Shape = { kind: "circle"; radius: number } | { kind: "square"; side: number };
function isCircle(s: Shape): s is { kind: "circle"; radius: number } {
  return s.kind === "circle";
}
const s: Shape = { kind: "circle", radius: 5 };
if (isCircle(s)) console.log(s.radius);

Generic Type Guards

Type guards can be written generically too — a generic guard can preserve the relationship between whatever input type it received and the more specific type it narrows down to.

Example: Generic Type Guards

typescript
function isOfType<T>(value: unknown, check: (v: unknown) => boolean): value is T {
  return check(value);
}
const val: unknown = 42;
if (isOfType<number>(val, (v) => typeof v === "number")) console.log(val + 1);

Using Guards in Arrays

Custom guards work especially well passed straight into array methods like filter — TypeScript recognizes a predicate-shaped guard function and infers a narrower array type for the filtered result automatically.

Example: Using Guards in Arrays

typescript
const values: (string | null)[] = ["a", null, "b"];
function isString(v: string | null): v is string {
  return v !== null;
}
const strings = values.filter(isString);
console.log(strings);
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Returning boolean instead of value is string, so the caller's type is not narrowed.
  2. Writing a predicate that lies, such as return true or checking only one property, which makes TypeScript trust wrong types.
  3. Forgetting that the guard narrows only the argument that was passed, not a copy stored in a different variable.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.