Python Type Hints - How to Use TypedDict2021-05-10
Take this function:
What type hint should we add for its return value?
We could use
It’s true the function does return a
dict, but it’s an incomplete type.
dict without any parameters is equivalent to
dict[Any, Any], and
Any disables type checking.
This would mean our return
dict’s keys and values would not be type checked in callers.
For example, mypy wouldn’t see any problem with this code:
But it crashes with a
Let’s get rid of that
Okay, what about
We can improve on just
dict by parameterizing the types of its keys and values:
Now we’re accurately declaring the type of the keys as
str, which is great.
As the return values have mixed types, using
object is technically correct.
It conveys “this could be anything” better than
But it’s too restrictive, and the values’ types are now unknown at call sites.
For example, take this code:
mypy cannot tell that
sales is an
int, so it raises an error:
To declare the correct type of the value, we need to use
cast, for example:
This is not so useful as it places the burden of correct types away from the function into call sites.
cast() is not verified, so we could have type errors still.
dict[str, int | str | list[str]] ?
We can use the typing union operator,
|, to declare the possible types of values:
This constrains our values to be
The union type is more accurate than
object, which allowed literally infinite differen types.
But it does have a drawback - the type checker has has to assume each value could be any of the unioned types.
For example, we might try again to use
"sales" as an
But mypy tells us that the division operation won’t work in the cases that
sales might be a
Again we’d need to use a nasty
This comes with the same problems as before.
Aha - a
We now arrive at solution in the title.
TypedDict allows us to declare a structure for
dicts, mapping their keys (strings) to the types of their values.
TypedDict was specified in PEP 589 and introduced in Python 3.8.
On older versions of Python you can install it from typing-extensions.
We can use it like so:
Now we can access
"sales" without a
mypy knows that
sales is an
int, so it allows the file to pass:
And we can run the code without error:
Thanks to David Foster for creating
If you want to try checking
TypedDict types at runtime, check out his
May your types be ever more accurate,
🎉 My book Speed Up Your Django Tests is now up to date for Django 3.2. 🎉
Buy now on Gumroad
One summary email a week, no spam, I pinky promise.
- Python Type Hints - Duck typing with Protocol
- Python Type Hints - Use object instead of Any
- Python Type Hints - How to Create a TypedDict with Non-Identifier Keys
Tags: mypy, python
© 2021 All rights reserved.