Compatibility between TypeGuard and bool

The typing spec currently states:

[TypeGuard] is not a subtype of bool. Therefore, Callable[..., TypeGuard[int]] is not assignable to Callable[..., bool] .

That means that the following program should be rejected by type checkers:

from itertools import count
from typing import TypeGuard, Callable, Iterable

def filtered_count(pred: Callable[[int], bool]) -> Iterable[int]:
    for i in count():
        if pred(i):
            yield i

def is_even_int(x: object) -> TypeGuard[int]:
    return isinstance(x, int) and x % 2 == 0

for i in filtered_count(is_even_int):

This is passing a function returning a TypeGuard to a parameter of type Callable[[int], bool], and the spec explicitly says that is not allowed.

However, both mypy and pyright accept this program without errors. It works fine at runtime, and I don’t see any soundness problems that result from accepting it.

The rule in the spec derives from PEP 647 (which created TypeGuard) and was added in this PR. @erictraut told me that the change derived from feedback by Guido, but I haven’t been able to find a more precise motivation.

I propose to change the spec so that Callable[..., TypeGuard[...]] is a subtype of Callable[..., bool]. This brings the spec in line with the actual behavior of major type checkers.

The same reasoning applies to the new TypeIs special form I propose in PEP 742. For the moment I copied the TypeGuard restriction in the new PEP, but if the proposal in this post is accepted, I’ll change PEP 742 accordingly.


I’m in favor of your proposed change.

I’m also in favor. Regarding my original objection, it’s possible that I objected to TypeGuard[...] being considered a subtype of bool everywhere, rather than in the specific case where it’s the return type of a Callable type. FWIW, in my recollection I wasn’t the one who originally came up with this argument, but (a) memory is fungible, and (b) it doesn’t matter assuming we all agree on this now.

I have posted a proposed spec/test suite change:

And an issue for the Typing Council:

The Typing Council has accepted this change and I merged the change into the spec. Thanks everyone!

Next, I’ll update PEP 742 to match.