Code

src/types.ts — the Apod discriminated union

In the code column — src/types.ts, the domain types. ApodImage and ApodVideo are two interfaces, and Apod is their union.

Three details do all the work:

  • media_type: 'image' (not string) — a literal. That's the discriminant that enables narrowing.
  • hdurl?: string on ApodImage only, and ApodVideo doesn't have it at all. The ? means "optional" (string | undefined) — because even an image doesn't always have a high-res version.
  • copyright?: string on both — because any picture might have no owner (public domain).

The Apod union:

export type Apod = ApodImage | ApodVideo;

When you hold an Apod, the compiler doesn't know which one it is — so it won't let you reach hdurl until you check media_type. That's exactly what fixed lesson 15's TS2551: the check unlocks hdurl.

Rating — a literal union:

export type Rating = 0 | 1 | 2 | 3 | 4 | 5;   // not number

Verify (in your head or with tsc).

const pic: Apod = /* ... */;
pic.hdurl;                        // ❌ TS2339/2551 — not every Apod has hdurl
if (pic.media_type === 'image') {
  pic.hdurl;                      // ✅ now it exists
}
const r: Rating = 47;             // ❌ Type '47' is not assignable to type 'Rating'

Tip. The ? (optional) and the | (union) are two different "might not be there". hdurl?: string = "this field may be absent". Apod = ApodImage | ApodVideo = "this object may be one of two shapes". Together they describe the messy reality exactly: sometimes a video, sometimes no copyright, sometimes no high-res.