Skip to content

Commit b88f028

Browse files
committed
PEP 728: Incorporate discussions since last revision
- Mention indexed accesses and assignments with arbitrary keys, per Carl's feedback. - Prepare for submission by clearing the "open issues" sections, with edits when needed. - Include a reference to a prior discussion on `@final` addressing Victorien feedback (https://discuss.python.org/t/pep-728-typeddict-with-typed-extra-items/45443/138). - Update reference implementations. Signed-off-by: Zixuan James Li <p359101898@gmail.com>
1 parent bdc8b83 commit b88f028

File tree

1 file changed

+62
-17
lines changed

1 file changed

+62
-17
lines changed

peps/pep-0728.rst

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,34 @@ arguments of this type when constructed by calling the class object::
585585
year=2007,
586586
) # Not OK. Extra items not allowed
587587

588-
Interaction with Mapping[KT, VT]
589-
--------------------------------
588+
Supported and Unsupported Operations
589+
------------------------------------
590+
591+
This statement from the `typing spec
592+
<https://typing.python.org/en/latest/spec/typeddict.html#supported-and-unsupported-operations>`__
593+
still holds true.
594+
595+
Operations with arbitrary str keys (instead of string literals or other
596+
expressions with known string values) should generally be rejected.
597+
598+
This means that indexed accesses and assignments with arbitrary keys can still
599+
be rejected even when ``extra_items`` is specified.
600+
601+
Operations that already apply to ``NotRequired`` items should generally also
602+
apply to extra items, following the same rationale from the `typing spec
603+
<https://typing.python.org/en/latest/spec/typeddict.html#supported-and-unsupported-operations>`__
604+
:
605+
606+
The exact type checking rules are up to each type checker to decide. In some
607+
cases potentially unsafe operations may be accepted if the alternative is to
608+
generate false positive errors for idiomatic code.
609+
610+
Some operations are allowed due to the TypedDict being
611+
:term:`typing:assignable` to ``Mapping[str, VT]`` or ``dict[str, VT]``.
612+
The two following sections will expand on that.
613+
614+
Interaction with Mapping[str, VT]
615+
---------------------------------
590616

591617
A TypedDict type is :term:`typing:assignable` to a type of the form ``Mapping[str, VT]``
592618
when all value types of the items in the TypedDict
@@ -618,12 +644,12 @@ and ``items()`` on such TypedDict types::
618644
reveal_type(movie.items()) # Revealed type is 'dict_items[str, str]'
619645
reveal_type(movie.values()) # Revealed type is 'dict_values[str, str]'
620646

621-
Interaction with dict[KT, VT]
622-
-----------------------------
647+
Interaction with dict[str, VT]
648+
------------------------------
623649

624650
Because the presence of ``extra_items`` on a closed TypedDict type
625651
prohibits additional required keys in its :term:`typing:structural`
626-
:term:`typing:subtypes <subtype>`, we can determine if the TypedDict type and
652+
:term:`subtypes <subtype>`, we can determine if the TypedDict type and
627653
its structural subtypes will ever have any required key during static analysis.
628654

629655
The TypedDict type is :term:`typing:assignable` to ``dict[str, VT]`` if all
@@ -708,8 +734,25 @@ been removed in Python 3.13.
708734
Because this is a type-checking feature, it can be made available to older
709735
versions as long as the type checker supports it.
710736

711-
Open Issues
712-
===========
737+
Rejected Ideas
738+
==============
739+
740+
Use ``@final`` instead of ``closed`` Class Parameter
741+
-----------------------------------------------------
742+
743+
This was discussed `here <https://github.com/python/mypy/issues/7981>`__.
744+
745+
Quoting a relevant `comment
746+
<https://github.com/python/mypy/issues/7981#issuecomment-2080161813>`__
747+
from Eric Traut:
748+
749+
The @final class decorator indicates that a class cannot be subclassed. This
750+
makes sense for classes that define nominal types. However, TypedDict is a
751+
structural type, similar to a Protocol. That means two TypedDict classes
752+
with different names but the same field definitions are equivalent types.
753+
Their names and hierarchies don't matter for determining type consistency.
754+
For that reason, @final has no impact on a TypedDict type consistency rules,
755+
nor should it change the behavior of items or values.
713756

714757
Use a Special ``__extra_items__`` Key with the ``closed`` Class Parameter
715758
-------------------------------------------------------------------------
@@ -767,9 +810,6 @@ types altogether, but there are some disadvantages. `For example
767810
- The types don't appear in an annotation context, so their evaluation will
768811
not be deferred.
769812

770-
Rejected Ideas
771-
==============
772-
773813
Allowing Extra Items without Specifying the Type
774814
------------------------------------------------
775815

@@ -827,19 +867,24 @@ For example:
827867
[index: string]: number | string
828868
}
829869
830-
This is a known limitation discussed in `TypeScript's issue tracker
831-
<https://github.com/microsoft/TypeScript/issues/17867>`__,
832-
where it is suggested that there should be a way to exclude the defined keys
833-
from the index signature so that it is possible to define a type like
834-
``MovieWithExtraNumber``.
870+
While this restriction allows for sound indexed accesses with arbitrary keys,
871+
it comes with usability limitations discussed in `TypeScript's issue tracker
872+
<https://github.com/microsoft/TypeScript/issues/17867>`__.
873+
A suggestion was to allow excluding the defined keys from the index signature,
874+
to define a type like ``MovieWithExtraNumber``. This probably involves
875+
subtraction types, which is beyond the scope of this PEP.
835876

836877
Reference Implementation
837878
========================
838879

839-
An earlier revision of proposal is supported in `pyright 1.1.352
840-
<https://github.com/microsoft/pyright/releases/tag/1.1.352>`_, and `pyanalyze
880+
This is supported in `pyright 1.1.386
881+
<https://github.com/microsoft/pyright/releases/tag/1.1.386>`_, and an earlier
882+
revision is supported in `pyanalyze
841883
0.12.0 <https://github.com/quora/pyanalyze/releases/tag/v0.12.0>`_.
842884

885+
This is also supported in `typing-extensions 4.13.0rc1
886+
<https://pypi.org/project/typing-extensions/4.13.0rc1/>`_.
887+
843888
Acknowledgments
844889
===============
845890

0 commit comments

Comments
 (0)