Runtime type narrowing functions for safe type checking.
class=class="text-emerald-400">"text-gray">// User-defined type guard
interface Dog { kind: class=class="text-emerald-400">"text-emerald-400">'dog'; bark(): void }
interface Cat { kind: class=class="text-emerald-400">"text-emerald-400">'cat'; meow(): void }
type Animal = Dog | Cat
function isDog(animal: Animal): animal is Dog {
return animal.kind === class=class="text-emerald-400">"text-emerald-400">'dog'
}
class=class="text-emerald-400">"text-gray">// Discriminated union guard
type ApiResponse<T> =
| { status: class=class="text-emerald-400">"text-emerald-400">'success'; data: T }
| { status: class=class="text-emerald-400">"text-emerald-400">'error'; error: string }
function isSuccess<T>(res: ApiResponse<T>): res is { status: class=class="text-emerald-400">"text-emerald-400">'success'; data: T } {
return res.status === class=class="text-emerald-400">"text-emerald-400">'success'
}
class=class="text-emerald-400">"text-gray">// Null assertion guard
function assertDefined<T>(value: T | null | undefined, name: string): asserts value is T {
if (value === null || value === undefined) {
throw new Error(class="text-emerald-400">`Expected ${name} to be defined`)
}
}
class=class="text-emerald-400">"text-gray">// Usage
const response: ApiResponse<string> = { status: class=class="text-emerald-400">"text-emerald-400">'success', data: class=class="text-emerald-400">"text-emerald-400">'hello' }
if (isSuccess(response)) {
console.log(response.data) class=class="text-emerald-400">"text-gray">// TypeScript knows data exists
}Use type guards to narrow union types at runtime. isDog(animal) narrows the type so TypeScript knows you can call bark(). assertDefined throws if a value is null, letting TypeScript treat it as defined after the call.
Let's discuss how we can bring your idea to life. From initial concept to production-ready product — we've got you covered.