8000 "Sealed" `TypedDict`s that don't allow subtypes which introduce additional keys · Issue #1984 · python/typing · GitHub
[go: up one dir, main page]

Skip to content

"Sealed" TypedDicts that don't allow subtypes which introduce additional keys #1984

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

Closed
sh-at-cs opened this issue Apr 23, 2025 · 2 comments
Closed
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@sh-at-cs
Copy link
sh-at-cs commented Apr 23, 2025

Proposal

It might be useful if there was a possibility to mark a TypedDict as "sealed" (other naming suggestions welcome!), so that dicts with additional keys are not considered subtypes. E.g.:

from typing import TypedDict

class A(TypedDict, sealed=True):
  a: int

class AB(TypedDict):
  a: int
  b: int

ab: AB = {"a": 1, "b": 2}
a: A = ab  # error!

An alternative syntax may be to allow making any already-defined TypedDict sealed by wrapping it in Sealed[...]. E.g.:

class A(TypedDict):
  a: int

a: Sealed[A] = ab  # error!

Motivation

Situation

Consider trying to update() a TypedDict instance with an instance of a "partial" variant that only contains some of the former's keys:

from typing import TypedDict

class AB(TypedDict):
  a: int
  b: int

class A(TypedDict):
  a: int

ab: AB = {"a": 1, "b": 2}
a: A = {"a": 3}

ab.update(a)

Current type checking behavior

Both major type checkers will complain about this:

Mypy Pyright

error: Argument 1 to update of TypedDict has incompatible type A; expected TypedDict({'a': int, 'b'?: int}) [typeddict-item]

error: No overloads for update match the provided arguments (reportCallIssue)
error: Argument of type A cannot be assigned to parameter __m of type Partial[AB] in function update
  b is an incompatible type
    object is incompatible with int (reportArgumentType)

As can be seen from the error messages, the reason is that A allows subtypes which would have a key b just like AB, but the type of the value for that key could be different in these hypothetical subtypes from what it is in AB.

Current workaround & why it's insufficient

This issue can be worked around by adding all additional keys of AB as NotRequired keys on A:

from typing import NotRequired

class A(TypedDict):
  a: int
  b: NotRequired[int]

This will make ab.update(a) pass type checking.

But that is quite hacky:

  • If I have several different TypedDicts like AB, with different extra keys (beyond those in A), I have to introduce separate variants of A for each of them just to make update work correctly.
  • If AB has many more keys than A, I have to repeat all of them.
  • "Philosophically", it doesn't seem right that A should have any knowledge of AB's keys just to make the update operation work.

By contrast, if "sealed" TypedDicts were possible, I would only need the one sealed A and that's it.

Related proposals

  • @sealed decorator
    • This has less in common with this proposal than the name might suggest and I only bring it up at all because the name is the same: The @sealed decorator would apply to classes and forbid subclasses beyond those found in the same module. Meanwhile, this proposal is only about individual TypedDicts, shares none of the module-scoping logic, and can be seen as introducing a new kind of structural type, whereas @sealed is about nominal types.
@sh-at-cs sh-at-cs added the topic: feature Discussions about new features for Python's type annotations label Apr 23, 2025
@carljm
Copy link
Member
carljm commented Apr 23, 2025

You will probably be interested in https://peps.python.org/pep-0728/, which is currently under consideration, and includes this feature (under the name closed).

@sh-at-cs
Copy link
Author

Yep that's exactly it, thank you!! 👍💐

I'll close this then and just note that a related Mypy issue (linked from the above PEP) is:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

2 participants
0