Settings
Your save file

Progress lives in this browser, on this device. Download the save file to move it to another device, or to keep a copy in case this browser clears its storage.

Season 2
Week 8 of 12

Reading time · 3 min

One comp · scored

Up next

Week 9 · The Jury Speaks

Locked until you win

Week 8 · Jury Phase

The Feeds Leak

Typing API data

unknown vs any vs never, and typing a real WordPress REST response.

The WordPress REST API is a stranger you let into your data layer every single time a page loads. It has never seen your TypeScript types, it never will, and it will change shape the moment somebody adds a plugin or a custom field without telling you. Everything up to this point in the course has been about types you write yourself, on data you control. This week is about the boundary where that stops being true, which for bigbrotherjunkies.com is every single fetch call.

any vs unknown vs never: trust nobody, verify, impossible

Three types, three very different promises, and mixing them up is where a lot of TypeScript code quietly stops protecting anyone.

  • any turns off type checking for that value entirely. Read a property, call it, pass it anywhere, TypeScript stays silent the whole time. Trust everyone, verify nothing.
  • unknown is the safe version of the same idea. Anything can flow into an unknown, same as any, but you cannot do a single thing with it, no property access, no method call, until you have proven what it actually is with a real check. Trust nobody, verify first.
  • never is the type with no valid values at all, the type of a branch that is provably unreachable. You already met this in week three's exhaustiveness check. Impossible, not untrusted, a genuine promise that execution never reaches here.

The move this week leans on unknown specifically: it is the type that forces you to write the verification instead of skipping it.

Typing the boundary instead of trusting it

res.json() has always returned Promise<any>. That is not a bug, it is the honest admission that a JSON parser cannot know your data's shape, only that it parsed successfully. Left alone, that any quietly spreads through every function that touches the result. Stop it at the door.

The ES6 you write

async function loadComment(id) {
  const res = await fetch(`/wp-json/wp/v2/comments/${id}`)
  const data = await res.json()
  return data.content.rendered
}

The TS version

interface WpComment {
  id: number
  author_name: string
  content: { rendered: string }
}
 
function isWpComment(value: unknown): value is WpComment {
  if (typeof value !== 'object' || value === null) return false
  if (!('content' in value)) return false
  if (typeof value.content !== 'object' || value.content === null) return false
  if (!('rendered' in value.content)) return false
  return typeof value.content.rendered === 'string'
}
 
async function loadComment(id: number): Promise<string> {
  const res = await fetch(`/wp-json/wp/v2/comments/${id}`)
  const data: unknown = await res.json()
  if (!isWpComment(data)) throw new Error('The feeds are lying to you')
  return data.content.rendered
}

What changed

data goes from an implicit any, courtesy of res.json()'s own return type, to an explicit unknown, and a guard sits between it and the return statement. Nothing about the network call changed. What changed is that TypeScript now refuses to let loadComment read data.content.rendered until isWpComment has actually proven the shape at runtime, not just promised it in a type annotation.

Notice the guard is nothing but narrowing from week five, aimed at the network instead of at a local union: typeof for primitives, in to prove a property exists before reading it, one if-return-false per field. Nothing new syntactically, just pointed at data you did not create.

The 'content' in value check is doing real work, not decoration. value is typed unknown right up until that line. Every in check that follows narrows it a little further, the same control-flow narrowing from week five's guard, just chained field by field until value earns its way up to the full WpComment shape.

That is the whole lesson. Now prove it in the comp below.

Up next

Week 9 · The Jury Speaks

Discriminated unions

Locked until you win