@@ -1151,148 +1151,3 @@ section of the docs has a full description with an example, but in short, you wi
11511151need to give each TypedDict the same key where each value has a unique
11521152unique :ref: `Literal type <literal_types >`. Then, check that key to distinguish
11531153between your TypedDicts.
1154-
1155-
1156- User-Defined Type Guards
1157- ************************
1158-
1159- Mypy supports User-Defined Type Guards
1160- (:pep: `647 `).
1161-
1162- A type guard is a way for programs to influence conditional
1163- type narrowing employed by a type checker based on runtime checks.
1164-
1165- Basically, a ``TypeGuard `` is a "smart" alias for a ``bool `` type.
1166- Let's have a look at the regular ``bool `` example:
1167-
1168- .. code-block :: python
1169-
1170- from typing import List
1171-
1172- def is_str_list (val : List[object ]) -> bool :
1173- """ Determines whether all objects in the list are strings"""
1174- return all (isinstance (x, str ) for x in val)
1175-
1176- def func1 (val : List[object ]) -> None :
1177- if is_str_list(val):
1178- reveal_type(val) # Reveals List[object]
1179- print (" " .join(val)) # Error: incompatible type
1180-
1181- The same example with ``TypeGuard ``:
1182-
1183- .. code-block :: python
1184-
1185- from typing import List
1186- from typing import TypeGuard # use `typing_extensions` for Python 3.9 and below
1187-
1188- def is_str_list (val : List[object ]) -> TypeGuard[List[str ]]:
1189- """ Determines whether all objects in the list are strings"""
1190- return all (isinstance (x, str ) for x in val)
1191-
1192- def func1 (val : List[object ]) -> None :
1193- if is_str_list(val):
1194- reveal_type(val) # List[str]
1195- print (" " .join(val)) # ok
1196-
1197- How does it work? ``TypeGuard `` narrows the first function argument (``val ``)
1198- to the type specified as the first type parameter (``List[str] ``).
1199-
1200- .. note ::
1201-
1202- Narrowing is
1203- `not strict <https://www.python.org/dev/peps/pep-0647/#enforcing-strict-narrowing >`_.
1204- For example, you can narrow ``str `` to ``int ``:
1205-
1206- .. code-block :: python
1207-
1208- def f (value : str ) -> TypeGuard[int ]:
1209- return True
1210-
1211- Note: since strict narrowing is not enforced, it's easy
1212- to break type safety.
1213-
1214- However, there are many ways a determined or uninformed developer can
1215- subvert type safety -- most commonly by using cast or Any.
1216- If a Python developer takes the time to learn about and implement
1217- user-defined type guards within their code,
1218- it is safe to assume that they are interested in type safety
1219- and will not write their type guard functions in a way
1220- that will undermine type safety or produce nonsensical results.
1221-
1222- Generic TypeGuards
1223- ------------------
1224-
1225- ``TypeGuard `` can also work with generic types:
1226-
1227- .. code-block :: python
1228-
1229- from typing import Tuple, TypeVar
1230- from typing import TypeGuard # use `typing_extensions` for `python<3.10`
1231-
1232- _T = TypeVar(" _T" )
1233-
1234- def is_two_element_tuple (val : Tuple[_T, ... ]) -> TypeGuard[Tuple[_T, _T]]:
1235- return len (val) == 2
1236-
1237- def func (names : Tuple[str , ... ]):
1238- if is_two_element_tuple(names):
1239- reveal_type(names) # Tuple[str, str]
1240- else :
1241- reveal_type(names) # Tuple[str, ...]
1242-
1243- Typeguards with parameters
1244- --------------------------
1245-
1246- Type guard functions can accept extra arguments:
1247-
1248- .. code-block :: python
1249-
1250- from typing import Type, Set, TypeVar
1251- from typing import TypeGuard # use `typing_extensions` for `python<3.10`
1252-
1253- _T = TypeVar(" _T" )
1254-
1255- def is_set_of (val : Set[Any], type : Type[_T]) -> TypeGuard[Set[_T]]:
1256- return all (isinstance (x, type ) for x in val)
1257-
1258- items: Set[Any]
1259- if is_set_of(items, str ):
1260- reveal_type(items) # Set[str]
1261-
1262- TypeGuards as methods
1263- ---------------------
1264-
1265- A method can also serve as the ``TypeGuard ``:
1266-
1267- .. code-block :: python
1268-
1269- class StrValidator :
1270- def is_valid (self , instance : object ) -> TypeGuard[str ]:
1271- return isinstance (instance, str )
1272-
1273- def func (to_validate : object ) -> None :
1274- if StrValidator().is_valid(to_validate):
1275- reveal_type(to_validate) # Revealed type is "builtins.str"
1276-
1277- .. note ::
1278-
1279- Note, that ``TypeGuard ``
1280- `does not narrow <https://www.python.org/dev/peps/pep-0647/#narrowing-of-implicit-self-and-cls-parameters >`_
1281- types of ``self `` or ``cls `` implicit arguments.
1282-
1283- If narrowing of ``self `` or ``cls `` is required,
1284- the value can be passed as an explicit argument to a type guard function:
1285-
1286- .. code-block :: python
1287-
1288- class Parent :
1289- def method (self ) -> None :
1290- reveal_type(self ) # Revealed type is "Parent"
1291- if is_child(self ):
1292- reveal_type(self ) # Revealed type is "Child"
1293-
1294- class Child (Parent ):
1295- ...
1296-
1297- def is_child (instance : Parent) -> TypeGuard[Child]:
1298- return isinstance (instance, Child)
0 commit comments