This PEP adds two class parameters, closed and extra_items to type the extra items on a TypedDict. This addresses the need to define closed TypedDict types or to type a subset of keys that might appear in a dict while permitting additional items of a specified type.
A typing.TypedDict type can annotate the value type of each known item in a dictionary. However, due to structural assignability, a TypedDict can have extra items that are not visible through its type. There is currently no way to restrict the types of items that might be present in the TypedDict type’s consistent subtypes.
The current behavior of TypedDict prevents users from defining a TypedDict type when it is expected that the type contains no extra items.
Due to the possible presence of extra items, type checkers cannot infer more precise return types for .items() and .values() on a TypedDict. This can be resolved by defining a closed TypedDict type.
Another possible use case for this is a sound way to enable type narrowing with the in check:
Nothing prevents a dict that is assignable with Movie to have the author key, and under the current specification it would be incorrect for the type checker to narrow its type.
For supporting API interfaces or legacy codebase where only a subset of possible keys are known, it would be useful to explicitly specify extra items of certain value types.
However, the typing spec is more restrictive when checking the construction of a TypedDict, preventing users from doing this:
While the restriction is enforced when constructing a TypedDict, due to structural assignability, the TypedDict may have extra items that are not visible through its type. For example:
It is not possible to acknowledge the existence of the extra items through in checks and access them without breaking type safety, even though they might exist from some consistent subtypes of MovieBase:
Some workarounds have already been implemented to allow extra items, but none of them is ideal. For mypy, --disable-error-code=typeddict-unknown-key suppresses type checking error specifically for unknown keys on TypedDict. This sacrifices type safety over flexibility, and it does not offer a way to specify that the TypedDict type expects additional keys whose value types are assignable with a certain type.
PEP 692 adds a way to precisely annotate the types of individual keyword arguments represented by **kwargs using TypedDict with Unpack. However, because TypedDict cannot be defined to accept arbitrary extra items, it is not possible to allow additional keyword arguments that are not known at the time the TypedDict is defined.
Given the usage of pre-PEP 692 type annotation for **kwargs in existing codebases, it will be valuable to accept and type extra items on TypedDict so that the old typing behavior can be supported in combination with Unpack.
The new features introduced in this PEP would address several long-standing feature requests in the type system. Previous discussions include:
Suppose we want a type that allows extra items of type str on a TypedDict.
Index Signatures in TypeScript allow this:
This proposal aims to support a similar feature without syntax changes, offering a natural extension to the existing assignability rules.
We propose to add a class parameter extra_items to TypedDict. It accepts a type expression as the argument; when it is present, extra items are allowed, and their value types must be assignable to the type expression value.
An application of this is to disallow extra items. We propose to add a closed class parameter, which only accepts a literal True or False as the argument. It should be a runtime error when closed and extra_items are used at the same time.
Different from index signatures, the types of the known items do not need to be assignable to the extra_items argument.
There are some advantages to this approach:
This specification is structured to parallel PEP 589 to highlight changes to the original TypedDict specification.
If extra_items is specified, extra items are treated as non-required items matching the extra_items argument, whose keys are allowed when determining supported and unsupported operations.
By default extra_items is unset. For a TypedDict type that specifies extra_items, during construction, the value type of each unknown item is expected to be non-required and assignable to the extra_items argument. For example:
Here, extra_items=bool specifies that items other than 'name' have a value type of bool and are non-required.
The alternative inline syntax is also supported:
Accessing extra items is allowed. Type checkers must infer their value type from the extra_items argument:
extra_items is inherited through subclassing:
Here, 'year' in a is an extra key defined on Movie whose value type is int. 'other_extra_key' in b is another extra key whose value type must be assignable to the value of extra_items defined on MovieBase.
When neither extra_items nor closed=True is specified, closed=False is assumed. The TypedDict should allow non-required extra items of value type ReadOnly[object] during inheritance or assignability checks, to preserve the default TypedDict behavior. Extra keys included in TypedDict object construction should still be caught, as mentioned in TypedDict’s typing spec.
When closed=True is set, no extra items are allowed. This is equivalent to extra_items=Never, because there can’t be a value type that is assignable to Never. It is a runtime error to use the closed and extra_items parameters in the same TypedDict definition.
Similar to total, only a literal True or False is supported as the value of the closed argument. Type checkers should reject any non-literal value.
Passing closed=False explicitly requests the default TypedDict behavior, where arbitrary other keys may be present and subclasses may add arbitrary items. It is a type checker error to pass closed=False if a superclass has closed=True or sets extra_items.
If closed is not provided, the behavior is inherited from the superclass. If the superclass is TypedDict itself or the superclass does not have closed=True or the extra_items parameter, the previous TypedDict behavior is preserved: arbitrary extra items are allowed. If the superclass has closed=True, the child class is also closed:
As a consequence of closed=True being equivalent to extra_items=Never, the same rules that apply to extra_items=Never also apply to closed=True. While they both have the same effect, closed=True is preferred over extra_items=Never.
It is possible to use closed=True when subclassing if the extra_items argument is a read-only type:
This will be further discussed in a later section.
closed is also supported with the functional syntax:
It is an error to use Required[] or NotRequired[] with extra_items. total=False and total=True have no effect on extra_items itself.
The extra items are non-required, regardless of the totality of the TypedDict. Operations that are available to NotRequired items should also be available to the extra items:
For type checking purposes, Unpack[SomeTypedDict] with extra items should be treated as its equivalent in regular parameters, and the existing rules for function parameters still apply:
When the extra_items argument is annotated with the ReadOnly[] type qualifier, the extra items on the TypedDict have the properties of read-only items. This interacts with inheritance rules specified in Read-only Items.
Notably, if the TypedDict type specifies extra_items to be read-only, subclasses of the TypedDict type may redeclare extra_items.
Because a non-closed TypedDict type implicitly allows non-required extra items of value type ReadOnly[object], its subclass can override the extra_items argument with more specific types.
More details are discussed in the later sections.
extra_items is inherited in a similar way as a regular key: value_type item. As with the other keys, the inheritance rules and Read-only Items inheritance rules apply.
We need to reinterpret these rules to define how extra_items interacts with them.
First, it is not allowed to change the value of extra_items in a subclass unless it is declared to be ReadOnly in the superclass:
Second, extra_items=T effectively defines the value type of any unnamed items accepted to the TypedDict and marks them as non-required. Thus, the above restriction applies to any additional items defined in a subclass. For each item added in a subclass, all of the following conditions should apply:
For example:
An important side effect of the inheritance rules is that we can define a TypedDict type that disallows additional items:
Here, passing the value Never to extra_items specifies that there can be no other keys in MovieFinal other than the known ones. Because of its potential common use, there is a preferred alternative:
where we implicitly assume that extra_items=Never.
Let S be the set of keys of the explicitly defined items on a TypedDict type. If it specifies extra_items=T, the TypedDict type is considered to have an infinite set of items that all satisfy the following conditions.
For type checking purposes, let extra_items be a non-required pseudo-item when checking for assignability according to rules defined in the Read-only Items section, with a new rule added in bold text as follows:
The following examples illustrate these checks in action.
extra_items puts various restrictions on additional items for assignability checks:
where MovieWithYear (B) is not assignable to Movie (A) according to this rule:
When extra_items is specified to be read-only on a TypedDict type, it is possible for an item to have a narrower type than the extra_items argument:
This behaves the same way as if year: ReadOnly[str | int] is an item explicitly defined in Movie.
extra_items as a pseudo-item follows the same rules that other items have, so when both TypedDicts types specify extra_items, this check is naturally enforced:
A non-closed TypedDict type implicitly allows non-required extra keys of value type ReadOnly[object]. Applying the assignability rules between this type and a closed TypedDict type is allowed:
TypedDicts that allow extra items of type T also allow arbitrary keyword arguments of this type when constructed by calling the class object:
This statement from the typing spec still holds true.
Operations that already apply to NotRequired items should generally also apply to extra items, following the same rationale from the typing spec:
Some operations, including indexed accesses and assignments with arbitrary str keys, may be allowed due to the TypedDict being assignable to Mapping[str, VT] or dict[str, VT]. The two following sections will expand on that.
A TypedDict type is assignable to a type of the form Mapping[str, VT] when all value types of the items in the TypedDict are assignable to VT. For the purpose of this rule, a TypedDict that does not have extra_items= or closed= set is considered to have an item with a value of type ReadOnly[object]. This extends the current assignability rule from the typing spec.
For example:
Type checkers should infer the precise signatures of values() and items() on such TypedDict types:
By extension of this assignability rule, type checkers may allow indexed accesses with arbitrary str keys when extra_items or closed=True is specified. For example:
Defining the type narrowing behavior for TypedDict is out-of-scope for this PEP. This leaves flexibility for a type checker to be more/less restrictive about indexed accesses with arbitrary str keys. For example, a type checker may opt for more restriction by requiring an explicit 'x' in d check.
Because the presence of extra_items on a closed TypedDict type prohibits additional required keys in its structural subtypes, we can determine if the TypedDict type and its structural subtypes will ever have any required key during static analysis.
The TypedDict type is assignable to dict[str, VT] if all items on the TypedDict type satisfy the following conditions:
For example:
In this case, methods that are previously unavailable on a TypedDict are allowed, with signatures matching dict[str, VT] (e.g.: __setitem__(self, key: str, value: VT) -> None):
Notes on indexed accesses from the previous section still apply.
dict[str, VT] is not assignable to a TypedDict type, because such dict can be a subtype of dict:
At runtime, it is an error to pass both the closed and extra_items arguments in the same TypedDict definition, whether using the class syntax or the functional syntax. For simplicity, the runtime does not check other invalid combinations involving inheritance.
For introspection, the closed and extra_items arguments are mapped to two new attributes on the resulting TypedDict object: __closed__ and __extra_items__. These attributes reflect exactly what was passed to the TypedDict constructor, without considering superclasses.
If closed is not passed, the value of __closed__ is None. If extra_items is not passed, the value of __extra_items__ is the new sentinel object typing.NoExtraItems. (It cannot be None, because extra_items=None is a valid definition that indicates all extra items must be None.)
The new features introduced in this PEP can be taught together with the concept of inheritance as it applies to TypedDict. A possible outline could be:
The concept of a closed TypedDict should also be cross-referenced in documentation for related concepts. For example, type narrowing with the in operator works differently, perhaps more intuitively, with closed TypedDict types. In addition, when Unpack is used for keyword arguments, a closed TypedDict can be useful to restrict the allowed keyword arguments.
Because extra_items is an opt-in feature, no existing codebase will break due to this change.
Note that closed and extra_items as keyword arguments do not collide with other keys when using something like TD = TypedDict("TD", foo=str, bar=int), because this syntax has already been removed in Python 3.13.
Because this is a type-checking feature, it can be made available to older versions as long as the type checker supports it.
This was discussed here.
Quoting a relevant comment from Eric Traut:
In an earlier revision of this proposal, we discussed an approach that would utilize __extra_items__’s value type to specify the type of extra items accepted, like so:
where closed=True is required for __extra_items__ to be treated specially, to avoid key collision.
Some members of the community concern about the elegance of the syntax. Practically, the key collision with a regular key can be mitigated with workarounds, but since using a reserved key is central to this proposal, there are limited ways forward to address the concerns.
By introducing a new syntax that allows specifying string keys, we could deprecate the functional syntax of defining TypedDict types and address the key conflict issues if we decide to reserve a special key to type extra items.
For example:
This was proposed here by Jukka. The '_' key is chosen for not needing to invent a new name, and its similarity with the match statement.
This will allow us to deprecate the functional syntax of defining TypedDict types altogether, but there are some disadvantages. For example:
extra=True was originally proposed for defining a TypedDict that accepts extra items regardless of the type, like how total=True works:
Because it did not offer a way to specify the type of the extra items, the type checkers will need to assume that the type of the extra items is Any, which compromises type safety. Furthermore, the current behavior of TypedDict already allows untyped extra items to be present in runtime, due to structural assignability. closed=True plays a similar role in the current proposal.
Supporting intersections in Python’s type system requires a lot of careful consideration, and it can take a long time for the community to reach a consensus on a reasonable design.
Ideally, extra items in TypedDict should not be blocked by work on intersections, nor does it necessarily need to be supported through intersections.
Moreover, the intersection between Mapping[...] and TypedDict is not equivalent to a TypedDict type with the proposed extra_items special item, as the value type of all known items in TypedDict needs to satisfy the is-subtype-of relation with the value type of Mapping[...].
extra_items restricts the value type for keys that are unknown to the TypedDict type. So the value type of any known item is not necessarily assignable to extra_items, and extra_items is not necessarily assignable to the value types of all known items.
This differs from TypeScript’s Index Signatures syntax, which requires all properties’ types to match the string index’s type. For example:
While this restriction allows for sound indexed accesses with arbitrary keys, it comes with usability limitations discussed in TypeScript’s issue tracker. A suggestion was to allow excluding the defined keys from the index signature, to define a type like MovieWithExtraNumber. This probably involves subtraction types, which is beyond the scope of this PEP.
This is supported in pyright 1.1.386, and an earlier revision is supported in pyanalyze 0.12.0.
This is also supported in typing-extensions 4.13.0.
Thanks to Jelle Zijlstra for sponsoring this PEP and providing review feedback, Eric Traut who proposed the original design this PEP iterates on, and Alice Purcell for offering their perspective as the author of PEP 705.
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.
Source: https://github.com/python/peps/blob/main/peps/pep-0728.rst
Last modified: 2026-06-15 17:28:27 UTC