2024-07-17
TypeIs
PEP 742 adds TypeIs
, it is very similar to TypeGuard
(docs), but makes up for a particular shortcoming.
TypeIs
will be present in Python 3.13, but you can use it (at time of writing) currently - it is exists in typing_extensions>=4.10.0
and is supported by mypy>=1.10.1
.
First, some preamble:
from typing import Any, TypeVar, TypeGuard
from typing_extensions import TypeIs
T = TypeVar("T")
If we use a plain ol' isinstance
, types are correctly narrowed in both branches of this if
statement:
x: int | str
if isinstance_b(x, int):
reveal_type(x) # int
else:
reveal_type(x) # str
If we implement out own isinstance
using TypeGuard
to help the typechecker, this doesn't work properly (note that it does work in the positive case):
def isinstance_a(v: Any, cls: type[T]) -> TypeGuard[T]:
return isinstance(v, cls)
x: int | str
if isinstance_a(x, int):
reveal_type(x) # int
else:
reveal_type(x) # int | str
TypeIs
makes up for this, we can now correctly implement our own isinstance
for both branches, yay!
def isinstance_b(v: Any, cls: type[T]) -> TypeIs[T]:
return isinstance(v, cls)
x: int | str
if isinstance_b(x, int):
reveal_type(x) # int
else:
reveal_type(x) # str