My App
Phase 7 — Type Hints

Optional & Nested Types

A value that might be None, and combining container hints together

Optional — a value that might be None

You saw this briefly in Phase 3. | None marks a value as optional:

name: str | None = None

TypeScript:

let name: string | null = null;

Read str | None as "a string, or None" — same union-type idea as TypeScript's string | null, just with Python's own "no value" (Phase 1) instead of null.

This shows up constantly on function parameters that have a sensible default of "nothing provided":

def get_user(user_id: int, name: str | None = None) -> dict:
    ...

Nested types

Container hints can be combined — a list of dicts, a dict of lists, and so on. Read them inside-out: figure out the innermost type first, then wrap outward.

users: list[dict[str, str]]

Reading inside-out:

  1. dict[str, str] — a dict where both the keys and values are strings
  2. list[...] — a list of those dicts

So the whole thing means: "a list, where each item is a dict of string to string."

TypeScript:

let users: Array<Record<string, string>>;

You'll see this exact shape constantly — a list of dicts is how most APIs represent "many records", each record being one dict (Phase 2's nested-data example, now with hints on it).

That's enough for now

str | None, list[...], and dict[...] cover the vast majority of type hints you'll write day to day. Things like generics, Protocol, or Callable types are worth learning later, once you actually hit a case that needs them — not before.

On this page