"Starting in Python 3.15 and typing-extensions today, there are two dimensions to TypedDict and how keys and their existence are treated. The first dimension is whether the specified keys in a TypedDict are all required or not (controlled by the total argument or and NotRequired on a per-key basis). This represents whether every key specified in your TypedDict must be in the dictionary or not."
"I was writing some code where I was using httpx.get() and its params parameter. I decided to use a for the dictionary I was passing as the argument since it was for a REST API, where the potential keys were fully known. I then ran Pyrefly over my code and got an unexpected error about how "object" is not a subtype of "str". I had no object in my TypedDict, so I didn't understand what was going on. I tried Pyright and it also failed."
"But starting in Python 3.15, a second dimension has been introduced that affects whether the TypedDict is closed. By default, a dictionary that is typed to a TypedDict can have any optional keys that it wants. So with either of our example TypedDict above, you could have any number of extra keys, each with any value. So what is a type checker to do if you reference some key that isn't defined by the"
Code using httpx.get() with a TypedDict for params triggered type errors from Pyrefly and Pyright while ty accepted the code. TypedDict has two dimensions: whether specified keys are required (controlled by total or Required/NotRequired) and whether the TypedDict is closed or open to extra keys. TypedDict was introduced in Python 3.8 and Required/NotRequired arrived in Python 3.11. Starting in Python 3.15 and typing-extensions, a closedness dimension can restrict additional keys. By default TypedDicts are open and allow arbitrary extra keys and values.
Read at Tall, Snarky Canadian
Unable to calculate read time
Collection
[
|
...
]