diff --git a/docs/source/type_narrowing.rst b/docs/source/type_narrowing.rst index 25d6629aa694..035109df7e37 100644 --- a/docs/source/type_narrowing.rst +++ b/docs/source/type_narrowing.rst @@ -37,7 +37,8 @@ Type narrowing is contextual. For example, based on the condition, mypy will nar # Back outside of the ``if`` statement, the type isn't narrowed: reveal_type(arg) # Revealed type: "builtins.object" -Mypy understands the implications `return` or exception raising can have for what type an object could be: +Mypy understands the implications ``return`` or exception raising can have +for what type an object could be: .. code-block:: python @@ -295,3 +296,35 @@ TypeGuards as methods def is_child(instance: Parent) -> TypeGuard[Child]: return isinstance(instance, Child) + +Assignment expressions as TypeGuards +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes you might need to create a new variable and narrow it +to some specific type at the same time. +This can be achieved by using ``TypeGuard`` together +with `:= operator `_. + +.. code-block:: python + + from typing import TypeGuard # use `typing_extensions` for `python<3.10` + + def is_float(a: object) -> TypeGuard[float]: + return isinstance(a, float) + + def main(a: object) -> None: + if is_float(x := a): + reveal_type(x) # N: Revealed type is 'builtins.float' + reveal_type(a) # N: Revealed type is 'builtins.object' + reveal_type(x) # N: Revealed type is 'builtins.object' + reveal_type(a) # N: Revealed type is 'builtins.object' + +What happens here? + +1. We create a new variable ``x`` and assign a value of ``a`` to it +2. We run ``is_float()`` type guard on ``x`` +3. It narrows ``x`` to be ``float`` in the ``if`` context and does not touch ``a`` + +.. note:: + + The same will work with ``isinstance(x := a, float)`` as well.