Special typing construct for marking user-defined type predicate functions. ``TypeGuard`` can be used to annotate the return type of a user-defined type predicate function. ``TypeGuard`` only accepts a single type argument. At runtime, functions marked this way should return a boolean.
(self, parameters)
| 826 | |
| 827 | @_SpecialForm |
| 828 | def TypeGuard(self, parameters): |
| 829 | """Special typing construct for marking user-defined type predicate functions. |
| 830 | |
| 831 | ``TypeGuard`` can be used to annotate the return type of a user-defined |
| 832 | type predicate function. ``TypeGuard`` only accepts a single type argument. |
| 833 | At runtime, functions marked this way should return a boolean. |
| 834 | |
| 835 | ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static |
| 836 | type checkers to determine a more precise type of an expression within a |
| 837 | program's code flow. Usually type narrowing is done by analyzing |
| 838 | conditional code flow and applying the narrowing to a block of code. The |
| 839 | conditional expression here is sometimes referred to as a "type predicate". |
| 840 | |
| 841 | Sometimes it would be convenient to use a user-defined boolean function |
| 842 | as a type predicate. Such a function should use ``TypeGuard[...]`` or |
| 843 | ``TypeIs[...]`` as its return type to alert static type checkers to |
| 844 | this intention. ``TypeGuard`` should be used over ``TypeIs`` when narrowing |
| 845 | from an incompatible type (e.g., ``list[object]`` to ``list[int]``) or when |
| 846 | the function does not return ``True`` for all instances of the narrowed type. |
| 847 | |
| 848 | Using ``-> TypeGuard[NarrowedType]`` tells the static type checker that |
| 849 | for a given function: |
| 850 | |
| 851 | 1. The return value is a boolean. |
| 852 | 2. If the return value is ``True``, the type of its argument |
| 853 | is ``NarrowedType``. |
| 854 | |
| 855 | For example:: |
| 856 | |
| 857 | def is_str_list(val: list[object]) -> TypeGuard[list[str]]: |
| 858 | '''Determines whether all objects in the list are strings''' |
| 859 | return all(isinstance(x, str) for x in val) |
| 860 | |
| 861 | def func1(val: list[object]): |
| 862 | if is_str_list(val): |
| 863 | # Type of ``val`` is narrowed to ``list[str]``. |
| 864 | print(" ".join(val)) |
| 865 | else: |
| 866 | # Type of ``val`` remains as ``list[object]``. |
| 867 | print("Not a list of strings!") |
| 868 | |
| 869 | Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower |
| 870 | form of ``TypeA`` (it can even be a wider form) and this may lead to |
| 871 | type-unsafe results. The main reason is to allow for things like |
| 872 | narrowing ``list[object]`` to ``list[str]`` even though the latter is not |
| 873 | a subtype of the former, since ``list`` is invariant. The responsibility of |
| 874 | writing type-safe type predicates is left to the user. |
| 875 | |
| 876 | ``TypeGuard`` also works with type variables. For more information, see |
| 877 | PEP 647 (User-Defined Type Guards). |
| 878 | """ |
| 879 | item = _type_check(parameters, f'{self} accepts only single type.') |
| 880 | return _GenericAlias(self, (item,)) |
| 881 | |
| 882 | |
| 883 | @_SpecialForm |