From 3b913a452dcf870abfac3c41f3119c0d7007144d Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 21 Dec 2021 15:43:10 +0300 Subject: [PATCH] Documents explicit type aliases (#11800) Refs https://www.python.org/dev/peps/pep-0613/ Co-authored-by: Jelle Zijlstra --- docs/source/common_issues.rst | 53 ++++++++++++++++++++-------------- docs/source/kinds_of_types.rst | 16 +++++++++- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/docs/source/common_issues.rst b/docs/source/common_issues.rst index d3c1761bc994..9d6423137c41 100644 --- a/docs/source/common_issues.rst +++ b/docs/source/common_issues.rst @@ -638,39 +638,48 @@ Mypy has both type aliases and variables with types like ``Type[...]`` and it is 1. Variables with type ``Type[...]`` should be created by assignments with an explicit type annotations: -.. code-block:: python + .. code-block:: python - class A: ... - tp: Type[A] = A + class A: ... + tp: Type[A] = A -2. Aliases are created by assignments without an explicit type: +2. Aliases are created by assignments without an explicit type. -.. code-block:: python + .. code-block:: python + + class A: ... + Alias = A - class A: ... - Alias = A + Or you can also use :pep:`613` and explicit type aliases: + + .. code-block:: python + + from typing import TypeAlias # or `from typing_extensions` before `python3.10` + + class A: ... + Alias: TypeAlias = A 3. The difference is that aliases are completely known statically and can be used in type context (annotations): -.. code-block:: python + .. code-block:: python - class A: ... - class B: ... + class A: ... + class B: ... - if random() > 0.5: - Alias = A - else: - Alias = B # error: Cannot assign multiple types to name "Alias" without an explicit "Type[...]" annotation \ - # error: Incompatible types in assignment (expression has type "Type[B]", variable has type "Type[A]") + if random() > 0.5: + Alias = A + else: + Alias = B # error: Cannot assign multiple types to name "Alias" without an explicit "Type[...]" annotation \ + # error: Incompatible types in assignment (expression has type "Type[B]", variable has type "Type[A]") - tp: Type[object] # tp is a type variable - if random() > 0.5: - tp = A - else: - tp = B # This is OK + tp: Type[object] # tp is a type variable + if random() > 0.5: + tp = A + else: + tp = B # This is OK - def fun1(x: Alias) -> None: ... # This is OK - def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type + def fun1(x: Alias) -> None: ... # This is OK + def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type Incompatible overrides ---------------------- diff --git a/docs/source/kinds_of_types.rst b/docs/source/kinds_of_types.rst index 7cdedf671867..73a6acac1db8 100644 --- a/docs/source/kinds_of_types.rst +++ b/docs/source/kinds_of_types.rst @@ -362,7 +362,6 @@ is needed: .. code-block:: python - class Container: items: list[str] # No initializer @@ -522,6 +521,21 @@ assigning the type to a variable: another type -- it's equivalent to the target type except for :ref:`generic aliases `. +Since Mypy 0.930 you can also use explicit type aliases which are defined by :pep:`613`. + +Implicit type alias declaration rules create confusion when type aliases involve forward references, +invalid types, or violate other restrictions enforced on type alias declaration. +Because the distinction between an unannotated value and a type alias is implicit, +ambiguous or incorrect type alias declarations implicitly default to a valid value assignment. + +.. code-block:: python + + from typing import TypeAlias # or `from typing_extensions` before `python3.10` + + AliasType: TypeAlias = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]] + +Explicit type aliases are unambiguous and improve readability. + .. _named-tuples: Named tuples