Skip to content

Regression in support for idiomatic TypedDict discrimination? #10517

@alicederyn

Description

@alicederyn

#10378 removed support for the common usage of "in" to discriminate between TypedDicts, as in

class ResponseOne(TypedDict):
  one: str

class ResponseTwo(TypedDict):
  two: str

class ErrorResponse(TypedDict):
  error: str

Response = ResponseOne | ResponseTwo | ErrorResponse

def do_something_that_expects_response_one(response: Response) -> None:
  if "one" not in response:
    raise RuntimeError(f"Unexpected response: {response}")
  value = response["one"]
  print(f"Got what we expected: {value}")

As of this latest release, this now errors with e.g. "one" is not a defined key in "ResponseTwo"

playground link

In the absence of any approved PEP to indicate a TypedDict is closed, I believe this has made it impossible to express this idiomatic code? (Outside of hand-crafting TypeGuard functions for every single type.) Using PEP-728, for instance, would as I understand it result in type annotations that cannot be used by mypy.

mypy currently supports marking these discrimination types as @final to achieve this result, but pyright decided to simply allow the idiomatic option in the past. If this decision is being reversed, could we reintroduce the ability to "close" these TypedDicts with @final until such time as a PEP has been agreed and integrated into other type-checkers?

Metadata

Metadata

Assignees

No one assigned

    Labels

    addressed in next versionIssue is fixed and will appear in next published versionbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions