My impression is this is a cross between typing.cast and `isinstance` checks. What's the difference between this and `typing.cast`? It seems a little stricter, because the return type in the TypeGuard must be narrower than the input type?

-- Teddy

On Wed, Sep 30, 2020 at 2:40 PM Eric Traut <> wrote:
I occasionally receive questions from pyright users about extending type narrowing to handle cases that are not possible with today’s Python type system.

Typescript provides a useful facility called [user-defined type guards]( that allows users to extend the notion of type narrowing. It would be straightforward to add this idea to Python. Do others think this would be useful, and is there any interest in standardizing this?

Here’s a concrete proposal. We could add a new generic type called `TypeGuard` in the `typing` module. It would be a subclass of bool, defined simply as:

class TypeGuard(bool, Generic[_T]):

If any function or method accepts one parameter and returns a `TypeGuard` type, a type checker would assume that the argument passed to this function can be narrowed to the type specified in the `TypeGuard` type argument.

Here are a few examples:

from typing import Any, Generic, List, Tuple, TypeGuard, TypeVar

_T = TypeVar("_T")

def is_two_element_tuple(val: Tuple[_T, ...]) -> TypeGuard[Tuple[_T, _T]]:
    return TypeGuard(len(val) == 2)

def foo(names: Tuple[str, ...]):
    if is_two_element_tuple(names):
        reveal_type(names)  # Tuple[str, str]

def is_string_list(val: List[object]) -> TypeGuard[List[str]]:
    return TypeGuard(all(isinstance(x, str) for x in val))

def bar(stuff: List[Any]):
    if is_string_list(stuff):
        reveal_type(stuff)  # List[str]

Thoughts? Suggestions?


Eric Traut
Contributor to Pyright and Pylance
Microsoft Corp.
Typing-sig mailing list --
To unsubscribe send an email to
Member address: