Skip to content

Type narrowed to Never when using TypeIs with union of callables #18009

Closed

Description

@Viicos

playground

from typing import Any, Callable
from typing_extensions import TypeIs, assert_type, assert_never


def is_single_callable(c: Callable[[], Any] | Callable[[int], Any]) -> TypeIs[Callable[[int], Any]]:
    ...


def test(c: Callable[[], Any] | Callable[[int], Any]):
    if is_single_callable(c):
        reveal_type(c)
    else:
        # mypy thinks this is unreachable
        a: int = 1

While c could be narrowed to Callable[[], Any] in the else block, it is currently narrowed to Never. For reference, see this discussion.

Your Environment

  • Mypy version used: 1.12.1
  • Mypy command-line flags: --warn-unreachable
  • Python version used: 3.12

Activity

  1. brianschubert commented on Nov 26, 2024

    @brianschubert
    Collaborator

    It turns out this affects any union of a generic type (not just Callable). For example:

    def is_int_list(c: list[str] | list[int]) -> TypeIs[list[int]]:
        ...
    
    def foo(x: list[str] | list[int]) -> None:
        if is_int_list(x):
            reveal_type(x)  # N: Revealed type is "builtins.list[builtins.int]"
        else:
            reveal_type(x)  # E: Statement is unreachable
        reveal_type(x)      # N: Revealed type is "builtins.list[builtins.int]"
  2. added a commit that references this issue on Jun 21, 2025
    6886b7a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-type-narrowingConditional type narrowing / bindertopic-typeguard-typeisTypeGuard / TypeIs / PEP 647 / PEP 742

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions