Skip to content
Back to skills

Typescript Narrowing

ASecurity

Narrow union types safely with guards, discriminated unions, and exhaustiveness checks. Use when working with values that could be several types, or when the compiler will not let you access a property you know is there.

  • 7 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
ai-agentstypescriptrustgoapi

Works with

  • api

Security analysis

A100/100

Scanned September 5, 2026

npx -y skills add Amey-Thakur/AI-SKILLS --skill typescript-narrowing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Typescript Narrowing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Typescript Narrowing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/amey-thakur-typescript-narrowing/badge)](https://www.skillsdirectory.com/skills/amey-thakur-typescript-narrowing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: typescript-narrowing
description: Narrow union types safely with guards, discriminated unions, and exhaustiveness checks. Use when working with values that could be several types, or when the compiler will not let you access a property you know is there.
---

# TypeScript narrowing

Narrowing is how you go from "this could be several types" to "here it is
this one" in a way the compiler trusts. Done well, it makes union types
ergonomic and catches the case you forgot; done with casts, it throws away
the safety you turned strict mode on for.

## Method

1. **Narrow with the checks the compiler understands.** `typeof x ===
   "string"`, `x instanceof Date`, `"id" in x`, and truthiness checks all
   narrow the type in the branch that follows. Prefer these built-in
   narrowings; they need no maintenance and cannot lie.
2. **Model alternatives as discriminated unions.** Give each variant a
   common literal tag (`type Result = { status: "ok"; data: T } |
   { status: "error"; message: string }`) and switch on the tag: the
   compiler narrows each branch to the right variant and knows which
   fields exist. This is the single most useful TypeScript pattern for
   states, results, and events (see ui-state-machines).
3. **Make switches exhaustive.** In the `default` case, assign the value
   to `const _exhaustive: never = x`: if a new variant is added and not
   handled, the compiler errors here, turning a forgotten case into a
   build failure (see exhaustive-switches). This is how you find every
   place to update when a union grows.
4. **Write custom type guards for reusable narrowing.** A function
   returning `x is Foo` (`function isFoo(x: unknown): x is Foo`) narrows
   at every call site. Make the guard's body actually verify the shape it
   claims; a guard that lies is worse than a cast because it looks safe.
5. **Use assertion functions for invariants.** `function assert(cond):
   asserts cond` and `assertIsUser(x): asserts x is User` narrow by
   throwing on failure, useful at boundaries where absence is a bug, not
   a branch (see defensive-programming).
6. **Cast only as a last resort, and narrowly.** `as` overrides the
   compiler and is a promise you might be breaking; `as any` and `!`
   (non-null assertion) discard safety entirely. When unavoidable
   (interfacing with weak library types), isolate the cast at the
   boundary with a comment, and prefer a validated guard over a bare
   assertion (see request-validation for parsing untrusted input).

## Boundaries

- Narrowing reflects what the compiler can prove from your checks; a cast
  or a lying guard makes it prove the wrong thing, and the runtime error
  returns.
- Control-flow narrowing resets across function calls and awaits (the
  compiler cannot assume a value is unchanged); re-narrow after an
  `await` or extract to a local.
- Runtime data (API responses, JSON) is `unknown` until validated;
  narrowing a bare `any` gives false confidence, so parse at the edge
  (see ts-api-types, structured-output for the LLM analog).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…