Skip to content

typing.TypeGuard not eliminating type possibility when branching. #3450

@AlexanderHott

Description

@AlexanderHott

Note: if you are reporting a wrong signature of a function or a class in the standard library, then the typeshed tracker is better suited for this report: https://github.com/python/typeshed/issues.

Describe the bug
When using TypeGuards to determine a type, they do not exhaust the type in following type checks.

Expected behavior
After a type is used in one branch, it will not show up in another.

Screenshots or Code
Current

import typing as t

def str_not_int(x: str | int) -> t.TypeGuard[str]:
    return isinstance(x, str)

def f(x: str | int) -> None:
    if str_not_int(x):
        reveal_type(x)  # Type of "x" is "str"
    else:
        reveal_type(x)  # Type of "x" is "str | int"

def g(x: str| int) -> None:
    if str_not_int(x):
        reveal_type(x)  # Type of "x" is "str"
        return

    reveal_type(x)  # Type of "x" is "str | int"

Expected

import typing as t

def str_not_int(x: str | int) -> t.TypeGuard[str]:
    return isinstance(x, str)

def f(x: str | int) -> None:
    if str_not_int(x):
        reveal_type(x)  # Type of "x" is "str"
    else:
        # if x was of type "str" it would have been caught by the first "if"
        reveal_type(x)  # Type of "x" is "int"

def g(x: str| int) -> None:
    if str_not_int(x):
        reveal_type(x)  # Type of "x" is "str"
        return

    # if x was of type "str" the function would have returned
    reveal_type(x)  # Type of "x" is "int"

VS Code extension or command-line
Both the cli and the VSCode extension report the same behavior.
CLI: pyright 1.1.245
Extension: v1.1.245

Additional context
I noticed that other type checkers like mypy and pylance both have this "issue", and was wondering if this is the intended behavior. If so, is there any way to get rid of more complex types when branching (such as Callable[..., int] vs Callable[..., Awaitable[int]]?

Metadata

Metadata

Assignees

No one assigned

    Labels

    as designedNot a bug, working as intended

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions