TypeScriptTips

Make bugs impossible.
One TypeScript tip at a time.

I like the tricks :) – Kasia

Parse, don't cast (again)

APIs could return something that doesn't adhere to your expected response. It's always a good idea to parse values at the boundary of the system before they are sent in.

type User = {
  name: string
  dateOfBirth: string // "yyyy-mm-dd"
}

const format = (user: User) =>
  `${user.name} is ${
    2022 - parseInt(user.dateOfBirth.split("-")[0], 10)
  } years old`

fetch(URL)
  .then((response) => response.json())
  .then((user: User) => { // ⛔️ Casted any to User
    return format(user)
  })
  .then((str: string) => console.log(str))

// ⛔️ When the API changes
// dateOfBirth: string
// to epoch
// dateOfBirth: number
// this will error at run-time.
import { z } from "zod"

const UserSchema = z.object({
  name: z.string(),
  dateOfBirth: z.string()
})

type User = z.infer<typeof UserSchema>

fetch()
  .then((response) => response.json())
  .then((json) => UserSchema.safeParse(json))
  .then((result) => {
    if (result.success) {
      // ✅ user is a User
      return format(user)
    } else {
      // ✅ Must handle parse error
    }
  })
  .then((str: string) => console.log(str))