Skip to content

spec: Rewrite TypedDict spec #2072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

JelleZijlstra
Copy link
Member

This is an edit of the TypedDict spec for clarity and flow. My goal was to
unify the pieces of the spec that derive from the various PEPs into a coherent
whole. I removed excessive examples and motivations: the spec should specify,
not justify. The length of the spec chapter is reduced by more than half.

The general approach I took is to first define the kinds of TypedDicts that
can exist, then explain the syntax for defining TypedDicts, then discuss
other aspects of TypedDict types.

I introduce some new terminology around PEP 728 to make it easier to talk
about the different kinds of TypedDict. TypedDicts are defined to have a
property called openness, which can have three states:

  • Open: all TypedDicts prior to PEP 728
  • Closed: no extra keys are allowed (closed=True)
  • With extra items: extra_items=... from PEP 728

I retained existing text where it made sense but also wrote some from
scratch.

This is an edit of the TypedDict spec for clarity and flow. My goal was to
unify the pieces of the spec that derive from the various PEPs into a coherent
whole. I removed excessive examples and motivations: the spec should specify,
not justify. The length of the spec chapter is reduced by more than half.

This change is on top of python#2068 (adding PEP 728).

The general approach I took is to first define the kinds of TypedDicts that
can exist, then explain the syntax for defining TypedDicts, then discuss
other aspects of TypedDict types.

I introduce some new terminology around PEP 728 to make it easier to talk
about the different kinds of TypedDict. TypedDicts are defined to have a
property called openness, which can have three states:
- Open: all TypedDicts prior to PEP 728
- Closed: no extra keys are allowed (closed=True)
- With extra items: extra_items=... from PEP 728

I retained existing text where it made sense but also wrote some from
scratch.
@JelleZijlstra
Copy link
Member Author

Posted about this on Discuss: https://discuss.python.org/t/revision-of-the-typeddict-spec/102675

Copy link

@jorenham jorenham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I picked some nits; hope you don't mind.

Copy link

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through the changes and left some comments. Looks good to me overall!

JelleZijlstra and others added 2 commits August 17, 2025 18:10
Co-authored-by: Joren Hammudoglu <jhammudoglu@gmail.com>
@JelleZijlstra
Copy link
Member Author

Thanks for the feedback! I pushed some changes.

Copy link
Member

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, and much clearer! Thank you.

Copy link
Collaborator

@rchen152 rchen152 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, this is much better organized than before!

@srittau srittau added the topic: typing spec For improving the typing spec label Aug 20, 2025
Copy link
Collaborator

@erictraut erictraut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this @JelleZijlstra!

I left some comments for you to review regarding equivalency vs consistency.


Movie = TypedDict('Movie', {'name': str, 'year': int})
- If it is mutable in ``A``, it must also be mutable in ``B``, and the item type in ``B`` must be
:term:`equivalent` to the item type in ``A``. (It follows that for assignability, the two item types
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think equivalence is correct here. I think it should say "consistent with".

class Foo(TypedDict):
    x: list[int]

class Bar(Foo):
    x: list[Any] # OK

We should be very suspect if the word "equivalent" shows up anywhere in sublcassing or assignability rules in the spec.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rule list is specifically about subtyping, not assignability. There is a note that this implies that for assignability, you can read "consistency" wherever "equivalence" shows up. Perhaps it would be clearer to describe the assignability procedure, but subtyping is more fundamental.

Copy link
Collaborator

@erictraut erictraut Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think the current wording is confusing and not as useful to users of the type system or for type checker authors. I see your point about subtyping being more fundamental, but assignability rules are more important for understanding typing and for properly implementing a type checker. I doubt if any of the major type checkers have code that tests for subtyping. Pyright does not. It's all about assignability.

The note helps, but it doesn't cover all aspects of the description. For example, the note doesn't apply to the statement "If it is read-only in A, the item type in B must be a subtype of the item type in A". Without additional notes, the assignability rules are arguably ambiguous.


.. _typeddict-assignability:
- If ``B`` has an item with the same key, it must also be mutable, and its item type must be
:term:`equivalent` to the item type in ``A``. (As before, it follows that for assignability, the two item types
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should say "consistent with" rather than "equivalent to".

First, any TypedDict type is :term:`assignable` to ``Mapping[str, object]``.
- If ``B`` is closed, the check fails.
- If ``B`` has extra items, the extra items type must not be read-only and must
be :term:`equivalent` to the item type in ``A``.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistent with

must be a subtype of the extra items type in ``A``. Additionally, for any items in ``B`` that are not present in ``A``,
the item type must be a subtype of the extra items type in ``A``.
- If ``A`` has mutable extra items, ``B`` must also have mutable extra items, and the extra items type in ``B``
must be :term:`equivalent` to the extra items type in ``A``. Additionally, for any items in ``B`` that are not present in ``A``,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consistent with

the item type must be a subtype of the extra items type in ``A``.
- If ``A`` has mutable extra items, ``B`` must also have mutable extra items, and the extra items type in ``B``
must be :term:`equivalent` to the extra items type in ``A``. Additionally, for any items in ``B`` that are not present in ``A``,
the item type must be :term:`equivalent` to the extra items type in ``A``.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consistent with


def g(b: B) -> None:
f(b) # Type check error: 'B' not assignable to 'A'
- The TypedDict type has mutable :term:`extra items` of a type that is :term:`equivalent` to ``VT``.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistent with

c: C = {'x': 0, 'y': 'foo'}
g(c)
c['y'] + 'bar' # Runtime error: int + str
- The value type of the item is :term:`equivalent` to ``VT``.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistent with

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: typing spec For improving the typing spec
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants