Manuals / TypeScript / Ch 8

D · IntegrationIntermediate50 min read

8. Typing APIs & external data

TypeScript · 44 pages source format

API responses are unknown until validated. Type fetch JSON with interfaces. Zod or manual guards for runtime check. unknown vs any — always prefer unknown for external data. Typed environment variables and module augmentation preview.

What you'll learn

  • Typing fetch responses
  • unknown vs any
  • Type guards
  • Zod lite
  • Env typing

Type API responses

Define Post interface matching JSONPlaceholder. getPost(id: number): Promise<Post>. Trust but verify at boundaries.

interface Post {
  id: number
  userId: number
  title: string
  body: string
}

async function getPost(id: number): Promise<Post> {
  const res = await fetch(`${BASE}/posts/${id}`)
  if (!res.ok) throw new Error(`HTTP ${res.status}`)
  return res.json() as Promise<Post> // trust + validate in prod
}

Do this now

Type all fetch functions with explicit return types. No bare Promise<any>.

Clear?

unknown over any

any disables checking. unknown requires narrowing before use. JSON.parse returns any by default — cast to unknown first.

Do this now

Write parseJson(raw: string): unknown. Narrow with typeof/object check before use.

Clear?

Type guards

function isPost(val: unknown): val is Post { return typeof val === "object" && val !== null && "title" in val }.

Do this now

Implement isPost guard. Use in getPost before return.

Clear?

Zod lite (optional)

npm install zod. PostSchema = z.object({...}). PostSchema.parse(data) throws on mismatch — runtime + static types.

import { z } from "zod"

const PostSchema = z.object({
  id: z.number(),
  userId: z.number(),
  title: z.string(),
  body: z.string(),
})

type Post = z.infer<typeof PostSchema>

Do this now

Add Zod schema for Post. Parse response in getPost. Export type Post = z.infer<typeof PostSchema>.

Clear?

Typed environment

declare ImportMetaEnv in vite-env.d.ts. Validate env at startup. Fail fast on missing VITE_API_BASE.

Do this now

Add vite-env.d.ts with interface ImportMetaEnv { readonly VITE_API_BASE: string }.

Clear?

Checklist