Skip to content

Narrowing with "tags" on unions (of TypedDicts or normal classes) doesn't work with the match statement #16286

Closed
@tmke8

Description

@tmke8

Bug Report

Mypy has a feature where a union of TypedDicts can be narrowed down based on the value of entries: https://mypy.readthedocs.io/en/stable/literal_types.html#tagged-unions

But this doesn't seem to work with pattern matching.

To Reproduce

from typing import Literal, TypedDict

class A(TypedDict):
    tag: Literal["a"]
    name: str
    
class B(TypedDict):
    tag: Literal["b"]
    num: int
    
def f(d: A | B) -> None:
    if d["tag"] == "a":
        print(d["name"])
    elif d["tag"] == "b":
        print(d["num"])

def g(d: A | B) -> None:
    match d["tag"]:
        case "a":
            print(d["name"])  # E: TypedDict "B" has no key "name"
        case "b":
            print(d["num"])  # E: TypedDict "A" has no key "num"

https://mypy-play.net/?mypy=latest&python=3.11&gist=22cd1c2a185a5182b98e12c1e5dd33e2

Expected Behavior

The narrowing in function g should work the same as in function f.

Actual Behavior

main.py:20: error: TypedDict "B" has no key "name"  [typeddict-item]
main.py:22: error: TypedDict "A" has no key "num"  [typeddict-item]
Found 2 errors in 1 file (checked 1 source file)

The dictionaries are not correctly narrowed in the match branches.

Your Environment

See mypy-play link above.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions