Typed dictionaries¶
(Originally specified in PEP 589, with later additions: Required
and NotRequired in PEP 655, use with Unpack in PEP 692,
ReadOnly in PEP 705, and closed=True and extra_items= in PEP 728.)
A TypedDict type represents dict objects that contain only keys of
type str. There are restrictions on which string keys are valid, and
which values can be associated with each key. Values that inhabit a
TypedDict type must be instances of dict itself, not a subclass.
TypedDict types can define any number of items, which are string
keys associated with values of a specified type. For example,
a TypedDict may contain the item a: str, indicating that the key a
must map to a value of type str. Items may be either required,
meaning they must be present in every instance of the TypedDict type, or
non-required, meaning they may be omitted, but if they are present,
they must be of the type specified in the TypedDict definition. By default,
all items in a TypedDict are mutable, but items
may also be marked as read-only, indicating that they may not be
modified.
In addition to explicitly specified items, TypedDicts may allow additional
items. By default, TypedDicts are open, meaning they may contain an
unknown set of additional items. They may also be marked as closed,
in which case they may not contain any keys beyond those explicitly specified.
As a third option, they may be defined with extra items of a specific type.
In this case, there may be any number of additional items present at runtime, but
their values must be of the specified type. Extra items may or may not be
read-only. Thus, a TypedDict may be open, closed, or have extra items;
we refer to this property as the openness of the TypedDict. For many purposes,
an open TypedDict is equivalent to a TypedDict with read-only extra items of
type object, but certain behaviors differ; for example, the
TypedDict constructor of open TypedDicts does not
allow unrecognized keys.
A TypedDict is a structural type: independent TypedDict types may be assignable to each other based on their structure, even if they do not share a common base class. For example, two TypedDict types that contain the same items are equivalent. Nevertheless, TypedDict types may inherit from other TypedDict types to share common items. TypedDict types may also be generic.
Syntax¶
This section outlines the syntax for creating TypedDict types. There are two syntaxes: the class-based syntax and the functional syntax.
Class-based Syntax¶
A TypedDict type can be defined using the class definition syntax with
typing.TypedDict as a direct or indirect base class:
from typing import TypedDict
class Movie(TypedDict):
name: str
year: int
Movie is a TypedDict type with two items: 'name' (with type
str) and 'year' (with type int).
A TypedDict can also be created through inheritance from one or more other TypedDict types:
class BookBasedMovie(Movie):
based_on: str
This creates a TypedDict type BookBasedMovie with three items:
'name' (type str), 'year' (type int), and 'based_on' (type str).
See Inheritance for more details.
A generic TypedDict can be created by inheriting from Generic with a list
of type parameters:
from typing import Generic, TypeVar
T = TypeVar('T')
class Response(TypedDict, Generic[T]):
status: int
payload: T
Or, in Python 3.12 and newer, by using the native syntax for generic classes:
from typing import TypedDict
class Response[T](TypedDict):
status: int
payload: T
It is invalid to specify a base class other than TypedDict, Generic,
or another TypedDict type in a class-based TypedDict definition.
It is also invalid to specify a custom metaclass.
A TypedDict definition may also contain the following keyword arguments in the class definition:
total: a boolean literal (TrueorFalse) indicating whether all items are required (True, the default) or non-required (False). This affects only items defined in this class, not in any base classes, and it does not affect any items that use an explicitRequired[]orNotRequired[]qualifier. The value must be exactlyTrueorFalse; other expressions are not allowed.closed: a boolean literal (TrueorFalse) indicating whether the TypedDict is closed (True) or open (False). The latter is the default, except when inheriting from another TypedDict that is not open (see Inheritance), or when theextra_itemsargument is also used. As withtotal, the value must be exactlyTrueorFalse. It is an error to use this argument together withextra_items=.extra_items: indicates that the TypedDict has extra items. The argument must be a annotation expression specifying the type of the extra items. The type qualifierReadOnly[]may be used to indicate that the extra items are read-only. Other type qualifiers are not allowed. If the extra items type isNever, no extra items are allowed, so this is equivalent toclosed=True.
The body of the class definition defines the items of the TypedDict type.
It may also contain a docstring or pass statements (primarily to allow the creation of
an empty TypedDict). No other statements are allowed, and type checkers should report an
error if any are present. Type comments are not supported for creating TypedDict items.
An item definition takes the form of an attribute annotation, key: T. key is
an identifier and corresponds to the string key of the item, and T is an
annotation expression specifying the type of the item value. This annotation
expression contains a type expression, optionally qualified with one of the
type qualifiers Required, NotRequired, or ReadOnly.
These type qualifiers may be nested arbitrarily or wrapped in Annotated[]. It is
an error to use both Required and NotRequired in the same item definition.
An item is read-only if and only if the ReadOnly qualifier is used.
To determine whether an item is required or non-required, the following procedure is used:
If the
Requiredqualifier is present, the item is required.If the
NotRequiredqualifier is present, the item is non-required.If the
totalargument of the TypedDict definition isFalse, the item is non-required.Else, the item is required.
It is valid to use Required[] and NotRequired[] even for
items where it is redundant, to enable additional explicitness if desired.
Note that the value of total only affects items defined in the current class body,
not in any base classes. Thus, inheritance can be used to create a TypedDict that mixes
required and non-required items without using Required[] or NotRequired[].
The following example demonstrates some of these rules:
from typing import TypedDict, NotRequired, Required, ReadOnly, Annotated
class Movie(TypedDict):
name: str # required, not read-only
year: int # required, not read-only
director: NotRequired[str] # non-required, not read-only
rating: NotRequired[ReadOnly[float]] # non-required, read-only
invalid: Required[NotRequired[int]] # type checker error: both Required and NotRequired used
class PartialMovie(TypedDict, total=False):
name: str # non-required, not read-only
year: Required[int] # required, not read-only
score: ReadOnly[float] # non-required, read-only
Functional syntax¶
In addition to the class-based syntax, TypedDict types can be created using an alternative functional syntax. This syntax allows defining items with keys that are not valid Python identifiers, and it is compatible with older Python versions such as 3.5 and 2.7 that don’t support the variable definition syntax introduced in PEP 526. On the other hand, this syntax does not support inheritance.
The functional syntax resembles the traditional syntax for defining named tuples:
from typing import TypedDict
Movie = TypedDict('Movie', {'name': str, 'year': int})
The syntax comprises a call to TypedDict(), the result of which must be immediately
assigned to a variable with the same name as the first argument to TypedDict().
The call to TypedDict() must have two positional arguments. The first is a string
literal specifying the name of the TypedDict type. The second is a dictionary specifying
the items of the TypedDict. It must be a dictionary display expression,
not a variable or other expression that evaluates to a dictionary at runtime.
The keys of the dictionary must be string literals and the values must be
annotation expressions following the same rules as
the class-based syntax (i.e., the qualifiers Required, NotRequired, and
ReadOnly are allowed). In addition to the two positional arguments, total,
closed, and extra_items keyword arguments are also supported, with the same
semantics as in the class-based syntax.
Using TypedDict Types¶
Here is an example of how the type Movie can be used:
movie: Movie = {'name': 'Blade Runner',
'year': 1982}
An explicit Movie type annotation is generally needed, as
otherwise an ordinary dictionary type could be assumed by a type
checker, for backwards compatibility. When a type checker can infer
that a constructed dictionary object should be a TypedDict, an
explicit annotation can be omitted. A typical example is a dictionary
object as a function argument. In this example, a type checker is
expected to infer that the dictionary argument should be understood as
a TypedDict:
def record_movie(movie: Movie) -> None: ...
record_movie({'name': 'Blade Runner', 'year': 1982})
Another example where a type checker should treat a dictionary display as a TypedDict is in an assignment to a variable with a previously declared TypedDict type:
movie: Movie
...
movie = {'name': 'Blade Runner', 'year': 1982}
Operations on movie can be checked by a static type checker:
movie['director'] = 'Ridley Scott' # Error: invalid key 'director'
movie['year'] = '1982' # Error: invalid value type ("int" expected)
The code below should be rejected, since 'title' is not a valid
key, and the 'name' key is missing:
movie2: Movie = {'title': 'Blade Runner',
'year': 1982}
The created TypedDict type object is not a real class object. Here are the only uses of the type a type checker is expected to allow:
It can be used in type expressions to represent the TypedDict type.
It can be used as a callable object with keyword arguments corresponding to the TypedDict items; see The TypedDict constructor.
It can be used as a base class, but only when defining a derived TypedDict (see above).
In particular, TypedDict type objects cannot be used in
isinstance() tests such as isinstance(d, Movie). This is
consistent with how isinstance() is not supported for
other type forms such as list[str].
The TypedDict constructor¶
TypedDict types are callable at runtime and can be used as a constructor to create values that conform to the TypedDict type. The constructor takes only keyword arguments, corresponding to the items of the TypedDict. Example:
m = Movie(name='Blade Runner', year=1982)
When called, the TypedDict type object returns an ordinary dictionary object at runtime:
print(type(m)) # <class 'dict'>
Every required item must be provided as a keyword argument. Non-required items may be omitted. Whether an item is read-only has no effect on the constructor.
Closed and open TypedDicts allow no additional items beyond those explicitly defined, but TypedDicts with extra items allow arbitrary keyword arguments, which must be of the specified type. Example:
from typing import TypedDict, ReadOnly
class MovieWithExtras(TypedDict, extra_items=ReadOnly[int | str]):
name: str
year: int
m1 = MovieWithExtras(name='Blade Runner', year=1982) # OK
m2 = MovieWithExtras(name='The Godfather', year=1972, director='Francis Ford Coppola', rating=9) # OK
m3 = MovieWithExtras(name='Inception', year=2010, budget=160.0) # Type check error: budget must be int or str
Initialization from dictionary literals¶
Type checkers should also allow initializing a value of TypedDict type from a dictionary literal:
m: Movie = {'name': 'Blade Runner', 'year': 1982} # OK
Or from a call to dict() with keyword arguments:
m: Movie = dict(name='Blade Runner', year=1982) # OK
In these cases, extra keys should not be allowed unless the TypedDict
is defined to allow extra items. In this example, the director key is not defined in
Movie and is expected to generate an error from a type checker:
m: Movie = dict(
name='Alien',
year=1979,
director='Ridley Scott') # error: Unexpected key 'director'
If a TypedDict has extra items, extra keys are allowed, provided their value matches the extra items type:
class ExtraMovie(TypedDict, extra_items=bool):
name: str
a: ExtraMovie = {"name": "Blade Runner", "novel_adaptation": True} # OK
b: ExtraMovie = {
"name": "Blade Runner",
"year": 1982, # Not OK. 'int' is not assignable to 'bool'
}
Here, extra_items=bool specifies that items other than 'name'
have a value type of bool and are non-required.
Inheritance¶
As discussed under Class-based Syntax, TypedDict types
can inherit from one or more other TypedDict types. In this case the
TypedDict base class should not be included. Example:
class BookBasedMovie(Movie):
based_on: str
Now BookBasedMovie has keys name, year, and based_on. It is
equivalent to this definition, since TypedDict types are structural types:
class BookBasedMovie(TypedDict):
name: str
year: int
based_on: str
Overriding items¶
Under limited circumstances, subclasses may redeclare items defined in a superclass with a different type or different qualifiers. Redeclaring an item with the same type and qualifiers is always allowed, although it is redundant.
If an item is mutable in a superclass, it must remain mutable in the subclass. Similarly,
mutable items that are required in a superclass must remain required in the subclass,
and mutable non-required items in the superclass must remain non-required in the subclass.
However, if the superclass item is read-only, a superclass item that is non-required
may be overridden with a required item in the subclass. A read-only item in a superclass
may be redeclared as mutable (that is, without the ReadOnly qualifier) in a subclass.
These rules are necessary for type safety.
If an item is read-only in the superclass, the subclass may redeclare it with a different type that is assignable to the superclass type. Otherwise, changing the type of an item is not allowed. Example:
class X(TypedDict):
x: str
y: ReadOnly[int]
z: int
class Y(X):
x: int # Type check error: cannot overwrite TypedDict field "x"
y: bool # OK: bool is assignable to int, and a mutable item can override a read-only one
z: bool # Type check error: key is mutable, so subclass type must be consistent with superclass
Openness¶
The openness of a TypedDict (whether it is open, closed, or has extra items) is inherited from its superclass by default:
class ClosedBase(TypedDict, closed=True):
name: str
class ClosedChild(ClosedBase): # also closed
pass
class ExtraItemsBase(TypedDict, extra_items=int | None):
name: str
class ExtraItemsChild(ExtraItemsBase): # also has extra_items=int | None
pass
However, subclasses may also explicitly use the closed and extra_items arguments
to change the openness of the TypedDict, but in some cases this yields a type checker error:
If the base class is open, all possible states are allowed in the subclass: it may remain open, it may be closed (with
closed=True), or it may have extra items (withextra_items=...).If the base class is closed, any child classes must also be closed.
If the base class has extra items, but they are not read-only, the child class must also allow the same extra items.
If the base class has read-only extra items, the child class may be closed, or it may redeclare its extra items with a type that is assignable to the base class type. Child classes may also have mutable extra items if the base class has read-only extra items.
For example:
class ExtraItemsRO(TypedDict, extra_items=ReadOnly[int | str]):
name: str
class ClosedChild(ExtraItemsRO, closed=True): # OK
pass
# OK, str is assignable to int | str, and mutable extra items can override read-only ones
class NarrowerChild(ExtraItemsRO, extra_items=str):
pass
When a TypedDict has extra items, this effectively defines the value type of any unnamed
items accepted to the TypedDict and marks them as non-required. Thus, there are some
restrictions on the items that can be added in subclasses. For each item
added in a subclass of a class with extra items of type T, the following rules must be followed:
If
extra_itemsis read-onlyThe item can be either required or non-required
The item’s value type must be assignable to
T
If
extra_itemsis not read-onlyThe item must be non-required
The item’s value type must be consistent with
T
For example:
class MovieBase(TypedDict, extra_items=int | None):
name: str
class MovieRequiredYear(MovieBase): # Not OK. Required key 'year' is not known to 'MovieBase'
year: int | None
class MovieNotRequiredYear(MovieBase): # Not OK. 'int | None' is not consistent with 'int'
year: NotRequired[int]
class MovieWithYear(MovieBase): # OK
year: NotRequired[int | None]
class BookBase(TypedDict, extra_items=ReadOnly[int | str]):
title: str
class Book(BookBase, extra_items=str): # OK
year: int # OK, since extra_items is read-only
Multiple inheritance¶
TypedDict types may use multiple inheritance to inherit items from multiple base classes. Here is an example:
class X(TypedDict):
x: int
class Y(TypedDict):
y: str
class XYZ(X, Y):
z: bool
The TypedDict XYZ has three items: x (type int), y
(type str), and z (type bool).
Multiple inheritance does not allow conflicting types for the same item:
class X(TypedDict):
x: int
class Y(TypedDict):
x: str
class XYZ(X, Y): # Type check error: cannot overwrite TypedDict field "x" while merging
xyz: bool
Subtyping and assignability¶
Because TypedDict types are structural types, a TypedDict T1 is assignable to another
TypedDict type T2 if the two are structurally compatible, meaning that all operations that
are allowed on T2 are also allowed on T1. For similar reasons, TypedDict types are
generally not assignable to any specialization of dict or Mapping, other than Mapping[str, object],
though certain closed TypedDicts and TypedDicts with extra items may be assignable
to these types.
The rest of this section discusses the subtyping rules for TypedDict in more detail. As with any type, the rules for assignability can be derived from the subtyping rules using the materialization procedure. Generally, this means that where “equivalent” is mentioned below, the consistency relation can be used instead when implementing assignability, and where “subtyping” between elements of a TypedDict is mentioned, assignability can be used instead when implementing assignability between TypedDicts.
Subtyping between TypedDict types¶
A TypedDict type B is a subtype of a TypedDict type A if
and only if all of the conditions below are satisfied. For the purposes of these conditions,
an open TypedDict is treated as if it had read-only extra items of type object.
The conditions are as follows:
For each item in
A:If it is required in
A:It must also be required in
B.If it is read-only in
A, the item type inBmust be a subtype of the item type inA. (For assignability between two TypedDicts, the first item must instead be assignable to the second.)If it is mutable in
A, it must also be mutable inB, and the item type inBmust be equivalent to the item type inA. (It follows that for assignability, the two item types must be consistent.)
If it is non-required in
A:If it is read-only in
A:If
Bhas an item with the same key, its item type must be a subtype of the item type inA.Else:
If
Bis closed, the check succeeds.If
Bhas extra items, the extra items type must be a subtype of the item type inA.
If it is mutable in
A:If
Bhas an item with the same key, it must also be mutable, and its item type must be equivalent to the item type inA.Else:
If
Bis closed, the check fails.If
Bhas extra items, the extra items type must not be read-only and must be equivalent to the item type inA.
If
Ais closed,Bmust also be closed, and it must not contain any items that are not present inA.If
Ahas read-only extra items,Bmust either be closed or also have extra items, and the extra items type inBmust be a subtype of the extra items type inA. Additionally, for any items inBthat are not present inA, the item type must be a subtype of the extra items type inA.If
Ahas mutable extra items,Bmust also have mutable extra items, and the extra items type inBmust be equivalent to the extra items type inA. Additionally, for any items inBthat are not present inA, the item type must be equivalent to the extra items type inA.
The intuition behind these rules is that any operation that is valid on A must also be valid and safe on B.
For example, any key access on A that is guaranteed to succeed (because the item is required) must also succeed on B,
and any mutating operation (such as setting or deleting a key) that is allowed on A must also be allowed on B.
An example where mutability is relevant:
class A(TypedDict):
x: int | None
class B(TypedDict):
x: int
def f(a: A) -> None:
a['x'] = None
b: B = {'x': 0}
f(b) # Type check error: 'B' not assignable to 'A'
b['x'] + 1 # Runtime error: None + 1
Subtyping with Mapping¶
A TypedDict type is a subtype of a type of the form Mapping[str, VT]
when all value types of the items in the TypedDict
are subtypes of VT. For the purpose of this rule, an open TypedDict is considered
to have read-only extra items of type object.
For example:
class MovieExtraStr(TypedDict, extra_items=str):
name: str
extra_str: MovieExtraStr = {"name": "Blade Runner", "summary": ""}
str_mapping: Mapping[str, str] = extra_str # OK
class MovieExtraInt(TypedDict, extra_items=int):
name: str
extra_int: MovieExtraInt = {"name": "Blade Runner", "year": 1982}
int_mapping: Mapping[str, int] = extra_int # Not OK. 'int | str' is not assignable with 'int'
int_str_mapping: Mapping[str, int | str] = extra_int # OK
As a consequence, every TypedDict type is assignable to Mapping[str, object].
Subtyping with dict¶
Generally, TypedDict types are not subtypes of any specialization of dict[...] type, since
dictionary types allow destructive operations, including clear(). They
also allow arbitrary keys to be set, which would compromise type safety.
However, a TypedDict with extra items may be a subtype of dict[str, VT],
provided certain conditions are met, because it introduces sufficient restrictions
for this subtyping relation to be safe.
A TypedDict type is a subtype of dict[str, VT] if the following conditions are met:
The TypedDict type has mutable extra items of a type that is equivalent to
VT.All items on the TypedDict satisfy the following conditions:
The value type of the item is equivalent to
VT.The item is not read-only.
The item is not required.
For example:
class IntDict(TypedDict, extra_items=int):
pass
class IntDictWithNum(IntDict):
num: NotRequired[int]
def f(x: IntDict) -> None:
v: dict[str, int] = x # OK
v.clear() # OK
not_required_num_dict: IntDictWithNum = {"num": 1, "bar": 2}
regular_dict: dict[str, int] = not_required_num_dict # OK
f(not_required_num_dict) # OK
In this case, some methods that are otherwise unavailable on a TypedDict are allowed,
with signatures matching dict[str, VT]
(e.g.: __setitem__(self, key: str, value: VT) -> None):
not_required_num_dict.clear() # OK
reveal_type(not_required_num_dict.popitem()) # OK. Revealed type is 'tuple[str, int]'
def f(not_required_num_dict: IntDictWithNum, key: str):
not_required_num_dict[key] = 42 # OK
del not_required_num_dict[key] # OK
On the other hand, dict[str, VT] is not assignable to any TypedDict type,
because such a type includes instances of subclasses of dict:
class CustomDict(dict[str, int]):
pass
def f(might_not_be_a_builtin_dict: dict[str, int]):
int_dict: IntDict = might_not_be_a_builtin_dict # Not OK
not_a_builtin_dict = CustomDict({"num": 1})
f(not_a_builtin_dict)
Supported and Unsupported Operations¶
Type checkers should support restricted forms of most dict
operations on TypedDict objects. The guiding principle is that
operations not involving Any types should be rejected by type
checkers if they may violate runtime type safety. Here are some of
the most important type safety violations to prevent:
A required key is missing.
A value has an invalid type.
A key that is not defined in the TypedDict type is added.
Read-only items are modified or deleted.
Items that are read-only may not be mutated (added, modified, or removed):
from typing import ReadOnly
class Band(TypedDict):
name: str
members: ReadOnly[list[str]]
blur: Band = {"name": "blur", "members": []}
blur["name"] = "Blur" # OK: "name" is not read-only
blur["members"] = ["Damon Albarn"] # Type check error: "members" is read-only
blur["members"].append("Damon Albarn") # OK: list is mutable
The exact type checking rules are up to each type checker to decide. In some cases potentially unsafe operations may be accepted if the alternative is to generate false positive errors for idiomatic code. Sometimes, operations on closed TypedDicts or TypedDicts with extra items are safe even if they would be unsafe on open TypedDicts, so type checker behavior may depend on the openness of the TypedDict.
Allowed keys¶
Many operations on TypedDict objects involve specifying a dictionary key.
Examples include accessing an item with d['key'] or setting an item with
d['key'] = value.
A key that is not a literal should generally be rejected, since its value is unknown during type checking, and thus can cause some of the above violations. This involves both destructive operations such as setting an item and read-only operations such as subscription expressions.
The use of a key that is not known to exist should be reported as an error,
even if this wouldn’t necessarily generate a runtime type error. These are
often mistakes, and these may insert values with an invalid type if
structural assignability hides the types of
certain items. For example, d['x'] = 1 should generate a type check error
if 'x' is not a valid key for d (which is assumed to be a TypedDict
type), unless d has mutable extra items of a compatible type.
Type checkers should allow final names with string values to be used instead of string literals in operations on TypedDict objects. For example, this is valid:
YEAR: Final = 'year'
m: Movie = {'name': 'Alien', 'year': 1979}
years_since_epoch = m[YEAR] - 1970
Similarly, an expression with a suitable literal type can be used instead of a literal value:
def get_value(movie: Movie,
key: Literal['year', 'name']) -> int | str:
return movie[key]
Specific operations¶
This section discusses some specific operations in more detail.
As an exception to the general rule around non-literal keys,
d.get(e)ande in dshould be allowed for TypedDict objects, for an arbitrary expressionewith typestr. The motivation is that these are safe and can be useful for introspecting TypedDict objects. The static type ofd.get(e)should be the union of all possible item types indif the string value ofecannot be determined statically. (This simplifies toobjectifdis open.)clear()is not safe on open TypedDicts since it could remove required items, some of which may not be directly visible because of structural assignability. However, this method is safe on closed TypedDicts and TypedDicts with extra items if there are no required or read-only items and there cannot be any subclasses with required or read-only items.popitem()is similarly unsafe on many TypedDicts, even if all known items are non-required.del obj['key']should be rejected unless'key'is a non-required, mutable key.Type checkers may allow reading an item using
d['x']even if the key'x'is not required, instead of requiring the use ofd.get('x')or an explicit'x' in dcheck. The rationale is that tracking the existence of keys is difficult to implement in full generality, and that disallowing this could require many changes to existing code. Similarly, type checkers may allow indexed accesses with arbitrary str keys when a TypedDict is closed or has extra items. For example:def bar(movie: MovieExtraInt, key: str) -> None: reveal_type(movie[key]) # Revealed type is 'str | int'
The return types of the
items()andvalues()methods can be determined from the union of all item types in the TypedDict (which would includeobjectfor open TypedDicts). Therefore, type checkers should infer more precise types for TypedDicts that are not open:from typing import TypedDict class MovieExtraInt(TypedDict, extra_items=int): name: str def foo(movie: MovieExtraInt) -> None: reveal_type(movie.items()) # Revealed type is 'dict_items[str, str | int]' reveal_type(movie.values()) # Revealed type is 'dict_values[str, str | int]'
The
update()method should not allow mutating a read-only item. Therefore, type checkers should error if a TypedDict with a read-only item is updated with another TypedDict that declares that item:class A(TypedDict): x: ReadOnly[int] y: int a1: A = {"x": 1, "y": 2} a2: A = {"x": 3, "y": 4} a1.update(a2) # Type check error: "x" is read-only in A
Unless the declared value is of bottom type (
Never):class B(TypedDict): x: NotRequired[typing.Never] y: ReadOnly[int] def update_a(a: A, b: B) -> None: a.update(b) # Accepted by type checker: "x" cannot be set on b
Note: Nothing will ever match the
Nevertype, so an item annotated with it must be absent.
Backwards Compatibility¶
To retain backwards compatibility, type checkers should not infer a TypedDict type unless it is sufficiently clear that this is desired by the programmer. When unsure, an ordinary dictionary type should be inferred. Otherwise existing code that type checks without errors may start generating errors once TypedDict support is added to the type checker, since TypedDict types are more restrictive than dictionary types. In particular, they aren’t subtypes of dictionary types.