microsoft / microsoft/pyright

TypeIs Does Not Properly Narrow Generics

Open
#10,509 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

**Describe the bug**
When using `TypeIs` to narrow `SomeGeneric[SomeType] -> SomeType`, pyright incorrectly narrows to "object*" instead of `SomeType`. Because of this, the intersection in the other branch also cannot narrow.

**Code or Screenshots**
If possible, provide a minimal, self-contained code sample (surrounded by triple back ticks) to demonstrate the issue. The code should define or import all referenced symbols.

```python
# main.py
from typing_extensions import TypeIs, TypeVar, reveal_type

T = TypeVar("T")
type SomeType[T] = T | list[T] | set[T]

def checker[T](_: SomeType[T]) -> TypeIs[T]: ...

# TypeIs properly narrows a specific type
def logic_specific(data: SomeType[int]) -> None:
if checker(data):
reveal_type(data) # type of "data"" is "int"
else:
reveal_type(data) # type of "data" is "list[int] | set[int]"

# TypeIs seems to improperly narrow to the Generic and proper intersection
def logic_generic[T](data: SomeType[T]) -> None:
if checker(data):
reveal_type(data) # type of "data" is "object*"
else:
reveal_type(
data
) # type of "data" is "object* | list[T@logic_generic] | set[T@logic_generic]"
```

However, with mypy, I do not see this issue. `mypy main.py` will yield:

```
main.py:15: note: Revealed type is "builtins.int"
main.py:17: note: Revealed type is "Union[builtins.list[builtins.int], builtins.set[builtins.int]]"
main.py:23: note: Revealed type is "T`-1"
main.py:26: note: Revealed type is "Union[builtins.list[T`-1], builtins.set[T`-1]]"
Success: no issues found in 1 source file
```

**VS Code extension or command-line**

I have confirmed I get this issue on not just pyright, but other LSPs built ontop of it (e.g. pylance in my VSCODE (v1.100.1) and basedpyright in neovim (0.11.0) ). I have checked on the following versions of python: 3.11, 3.12, and 3.13. Note that I did have to change the syntax and such on older versions of python.

Contributor guide

Open the contributing guide

Research direction

Start with the self-contained reproduction in main.py and run it through pyright, checking the reveal_type results for logic_specific and logic_generic against the expected types shown in the issue. Trace the generic TypeIs narrowing behavior from the relevant type-analysis entry point, then verify that both branches preserve T and the list/set intersection.

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
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.