Hi! I propose preserving a string literal immediately following a type statement as the resulting alias object’s __doc__ attribute, with support in pydoc to display it in help(), and making that docstring retrievable from ast.TypeAlias.
type Timeout = float | None
"""
Maximum wait in seconds.
Use None to wait indefinitely, or zero to return immediately.
"""
Under this proposal, Timeout.__doc__ would contain that documentation, and help(Timeout) would be:
Help on type alias Timeout in module mymodule:
type Timeout = float | None
Maximum wait in seconds.
Use None to wait indefinitely, or zero to return immediately.
Lazy value access:
__value__
Lazily evaluated value of the type alias.
evaluate_value
Evaluation function for __value__.
See help(typing.TypeAliasType) for the full type alias interface.
Motivation
The type statement creates a dedicated runtime object, so it can carry its own documentation, as classes and functions do.
Keeping the docstring on the type alias would let help() and other inspection tools read it at runtime without finding or parsing the source file. The documentation would also stay with the alias when it is re-exported or passed to another component.
Currently, help() on type aliases displays generic information about TypeAliasType, as shown in #156925.
Several tools already support documentation for type aliases exactly in the proposed format. Pyright supports docstrings following type statements (since 2023), Sphinx’s autotype documents PEP 695 aliases and their docstrings (since 2025), and Pylint recognises these strings as documentation (since 2023).
Runtime documentation could also be consumed by third-party frameworks. For example, frameworks that already recognize TypeAliasType (such as Pydantic) could choose to use __doc__ as descriptive metadata. Such integrations would be up to those projects.
Prototype
I have implementations of compiler and runtime support and pydoc support that formats the interface of type aliases and distinguishes type aliases from other module members.
Aliases created through the TypeAliasType constructor can be documented by assigning to __doc__, as there is no new constructor parameter.
Technicalities
Saving / stripping the docstring
AST preprocessing records the following string in a new optional doc field on ast.TypeAlias.
Under -OO, preprocessing strips it instead, using shared handling for astfold_body and nested statement sequences (including a little bit of refactoring to improve readability). Additional docstrings (as specified in PEP 257) are also handled, i.e. they cannot replace the stripped docstring.
Reading the docstring from the AST
The field contains the original text and is available through ast.get_docstring().
For example, ast.get_docstring(tree.body[0]) returns "Maximum wait in seconds." for this tree:
>>> tree = ast.parse('type Timeout = float | None\n"Maximum wait in seconds."')
>>> print(ast.dump(tree, indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Timeout', ctx=Store()),
value=BinOp(
left=Name(id='float'),
op=BitOr(),
right=Constant(value=None)),
doc='Maximum wait in seconds.'),
Expr(
value=Constant(value='Maximum wait in seconds.'))])
Both ast.dump() and repr() display the string in the doc field and in the original Expr(Constant(...)) statement. Keeping the statement preserves the structure used by existing AST consumers, so tools can still find documentation in its original position. For an undocumented alias, node.doc is None and the default dump omits that field. ast.get_docstring(node) cleans indentation and surrounding blank lines; ast.get_docstring(node, clean=False) returns the original string stored in node.doc.
Open question: AST representation
The prototype stores the docstring in TypeAlias.doc while retaining the following string statement. If a tool changes one without updating the other, a populated doc field takes precedence during compilation, while ast.unparse() uses the statement. This is the current implementation’s behavior; I’d welcome feedback on what the specified behavior should be.
Another option is for doc to reference the original Constant node. That would share in-place edits, but visitors would reach the node through both references, and replacing one reference could still leave them pointing to different nodes. The representation and how AST transformations should handle it remain open for discussion.
Or, we could hide the doc attribute completely behind a private attribute only retrievable through ast.get_docstring().
help() integration
Like pydoc’s existing function-signature rendering, pydoc requests a string representation through annotationlib.Format.STRING to display help(). String-format evaluation can execute code with side effects (such as reifying lazy imports). If rendering raises an exception, it tries to extract the original expression from the source without evaluating it. If the source cannot be recovered, it displays a placeholder showing a representation of the exception and continues with the documentation.
The implementations include tests for docstring handling and text and HTML rendering.
What do you think of adding this support? I’d be interested in your use cases, concerns, and thoughts about any parts of the proposal.