python / python/mypy

Incorrect type narrowing on union of `TypedDict`

Open
#12,098 7 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-type-narrowing topic-typed-dict
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

from typing import Any, TypedDict

class _SessionData(TypedDict):
    created: int
    session: dict[str, Any]


class _EmptyDict(TypedDict):
    """Empty dict for typing."""


SessionData = _SessionData | _EmptyDict

data: SessionData

reveal_type(data)
a = data if data else None
reveal_type(a)
aiohttp_session/__init__.py:56: note: Revealed type is "Union[TypedDict('aiohttp_session._SessionData', {'created': builtins.int, 'session': builtins.dict[builtins.str, Any]}), TypedDict('aiohttp_session._EmptyDict', {})]"
aiohttp_session/__init__.py:58: note: Revealed type is "Union[TypedDict('aiohttp_session._EmptyDict', {}), None]"

I also get the same result if I make it not data. The _SessionData type just disappears for no reason and it keeps saying the empty dict will be the result regardless of the boolean check.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the provided TypedDict union example and checking the two reveal_type results reported from aiohttp_session/init.py. Trace mypy's boolean narrowing for the union and verify that both the non-empty and empty TypedDict branches are handled correctly for both data and not data.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.