Since Python 3.11, as per PEP 655, what you need is NotRequired:
class _trending(TypedDict):
allStores: NotRequired[bool]
category: str
date: str
average: List[int]
notice that you shouldn't use Optional in TypedDict, and only use (Not)Required
if you want to use TypedDict with Pydantic, you could refer this article
Since Python 3.11, as per PEP 655, what you need is NotRequired:
class _trending(TypedDict):
allStores: NotRequired[bool]
category: str
date: str
average: List[int]
notice that you shouldn't use Optional in TypedDict, and only use (Not)Required
if you want to use TypedDict with Pydantic, you could refer this article
I used this question as duplicate target, but noticed that another option is missing here.
If you don't like NotRequired (for example, if you have many required and many optional keys and don't want to repeat NotRequired many times) or don't want to bother with typing_extensions (rare case), you can tweak totality.
The following definitions of Main* are equivalent:
import sys
# You may also pick one without version check, of course
if sys.version_info < (3, 11):
from typing_extensions import TypedDict, Required, NotRequired
else:
from typing import TypedDict, Required, NotRequired
class Main1(TypedDict):
foo: int
bar: str
baz: NotRequired[int]
qux: NotRequired[str]
class Main2(TypedDict, total=False):
foo: Required[int]
bar: Required[str]
baz: int
qux: str
class _Main3(TypedDict):
foo: int
bar: str
class Main3(_Main3, total=False):
baz: int
qux: str
class _Main4(TypedDict, total=False):
baz: int
qux: str
class Main4(_Main4):
foo: int
bar: str
Here's PEP explanation of totality:
The totality flag only applies to items defined in the body of the TypedDict definition. Inherited items won’t be affected, and instead use totality of the TypedDict type where they were defined. This makes it possible to have a combination of required and non-required keys in a single TypedDict type.
Here's example of checking with definitions above:
Main1(foo=1, bar='bar', baz=2, qux='qux')
Main1(foo=1, bar='bar', baz=2)
Main1(foo=1, bar='bar')
Main1(foo=1, baz=2, qux='qux') # E: Missing key "bar" for TypedDict "Main1" [typeddict-item]
Main1(foo=1, bar='bar', who=None) # E: Extra key "who" for TypedDict "Main1" [typeddict-item]
Main2(foo=1, bar='bar', baz=2, qux='qux')
Main2(foo=1, bar='bar', baz=2)
Main2(foo=1, bar='bar')
Main2(foo=1, baz=2, qux='qux') # E: Missing key "bar" for TypedDict "Main2" [typeddict-item]
Main2(foo=1, bar='bar', who=None) # E: Extra key "who" for TypedDict "Main2" [typeddict-item]
Main3(foo=1, bar='bar', baz=2, qux='qux')
Main3(foo=1, bar='bar', baz=2)
Main3(foo=1, bar='bar')
Main3(foo=1, baz=2, qux='qux') # E: Missing key "bar" for TypedDict "Main3" [typeddict-item]
Main3(foo=1, bar='bar', who=None) # E: Extra key "who" for TypedDict "Main3" [typeddict-item]
Main4(foo=1, bar='bar', baz=2, qux='qux')
Main4(foo=1, bar='bar', baz=2)
Main4(foo=1, bar='bar')
Main4(foo=1, baz=2, qux='qux') # E: Missing key "bar" for TypedDict "Main4" [typeddict-item]
Main4(foo=1, bar='bar', who=None) # E: Extra key "who" for TypedDict "Main4" [typeddict-item]
You can fiddle with this in playground
NotRequired is exactly what you are looking for. Optional[int] means int | None, but the item is still required. Any item that is annotated as NotRequired[int] can be ommitted as stated in PEP 655.
Note: If you import Required or NotRequired from typing_extensions (on Python <3.11), you should also import TypedDict from typing_extensions.
So if your type-checker supports this feature, it should only complain about missing my_key1.
# Python >= 3.11
from typing import Optional, NotRequired, TypedDict
# Python < 3.11
from typing import Optional
from typing_extensions import NotRequired, TypedDict
class MyTypedDict(TypedDict):
my_key1: Optional[int]
my_key2: NotRequired[int]
my_variable = MyTypedDict()
# mypy error: Missing key "my_key1" for TypedDict "MyTypedDict"
# pyright error: Argument missing for parameter "my_key1"
You can mix required and optional values with inheritance and total. From the mypy docs
class MovieBase(TypedDict):
name: str
year: int
class Movie(MovieBase, total=False):
based_on: str
Moviehas required keysnameandyear, whilebased_oncan be left out when constructing an object
Hi folks I tried to keep the title as short and concise as possible, I often find myself struggling for hours in order to properly type annotate nested dictionaries in my code.
If the dict only has 1 level, it works well but with a tiny more complex ones like the following, I have a lot of trouble:
{"@context": "http://schema.org",
"@type": "VideoObject",
"url": "https://www.example.com/0000/adventures-music-videos.html",
"name": "sample movie",
"description": "example",
"thumbnailUrl": "thumbnail.com/1.jpg",
"uploadDate": "2023-11-29",
"duration": "PT2H20M20S",
"contentUrl": "sample_link",
"isAccessibleForFree": false,
"productionCompany": {"@type": "Organization",
"name": "Example",
"@id": "https://www.example.com/0000/studio/music-movies.html"},
"hasPart": [{"@type": "Clip",
"name": "scene 1",
"startOffset": 15,
"endOffset": 2126,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 2",
"startOffset": 2128,
"endOffset": 4114,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 3",
"startOffset": 4117,
"endOffset": 6055,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 4",
"startOffset": 6057,
"endOffset": 8414,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false}]}I tried dict[str, object] and I also tried a looong annotation with all the possible types separated by a pipe, but for now the only one that does not trigger mypy in strict mode is dict[str, Any].
Any clues as to what I might be doing wrong?