A tagged union of TypedDicts: LLM reply blocks
A model reply is a list of blocks, each with a Literal type tag. After the checker sees block["type"] == "text" it knows the block is a TextBlock. assert_never makes the checker fail if a third block type is added and render forgets it. At run time isinstance does not work on a TypedDict.
These tools describe specific shapes: TypedDict labels the keys of a dictionary, NamedTuple gives tuple fields names, Literal allows only listed values, Final marks a constant, and Self, Annotated and @override cover methods that return their own class, extra metadata and overriding.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Define a TypedDict named ToolCall with name: str and arguments: dict[str, str], create one, and print its __required_keys__ sorted.
Define a NamedTuple Rgb with r, g, b ints and print Rgb(255, 0, 0) and its g value.
Define a type Mode = Literal["fast", "slow"] and print its allowed values using get_args.
Explain it without notes
What is a TypedDict at run time, and what does it give you at all?
When would you use Literal instead of str?
Why is -> Self better than naming the class when a method returns self?
How does a NamedTuple differ from a plain tuple and from a dataclass?
Can you validate that a dictionary matches a TypedDict at run time with isinstance? What would you do instead?
Expected output
Let me check the weather.
[calls weather with {'city': 'Pune'}]
TypeError: TypedDict does not support instance and class checks