Modernize Python Type Hints (Optional → | None, typing → builtins)
Convert old Python type hints to modern syntax — typing.List → list, Optional[X] → X | None, Union → |. In your browser.
Why use this tool?
Use the Type Hint Modernizer to upgrade legacy annotations to the cleaner Python 3.10+ syntax in one paste. It rewrites typing.List/Dict/Tuple to the builtin generics, turns Optional[X] into X | None and Union[A, B] into A | B, and removes the now-unneeded typing imports — the same changes pyupgrade and Ruff's UP rules make, but instantly and with no install.
from typing import List, Dict, Optional, Union, Iterable
def load_users(
ids: Iterable[int],
filters: Optional[Dict[str, str]] = None,
) -> Union[List[dict], None]:
"""Fetch users by id, optionally filtered."""
return NoneConverts typing.List/Dict/Tuple/Set → builtins,Optional[X] → X | None,Union[A, B] → A | B, moves Sequence/Iterable/Mapping → collections.abc, and cleans typing imports. Review the diff before committing.
About Modernize Python Type Hints
The Modernize Python Type Hints tool rewrites older typing syntax into the modern equivalents introduced in recent Python versions. Two PEPs drive most of it: PEP 585 (Python 3.9+) lets you subscript the builtin collection types directly, so typing.List[int] becomes list[int] and typing.Dict[str, int] becomes dict[str, int]; and PEP 604 (Python 3.10+) adds the | union operator, so Optional[X] becomes X | None and Union[A, B] becomes A | B.
The result is shorter, easier to read, and free of a whole layer of typing imports. Modern linters actively push this style — Ruff's UP006/UP007/UP045 rules and the pyupgrade tool make exactly these changes — so modernizing keeps your codebase consistent with current standards and quiets those warnings.
It also re-homes the abstract base classes that PEP 585 moved out of typing — Sequence, Iterable, Mapping, MutableMapping, Callable and friends now come from collections.abc — so a 'from typing import Sequence' becomes 'from collections.abc import Sequence' (the usage name is unchanged), which is the change Ruff's UP035 rule makes.
It works by rewriting the annotations in place rather than reparsing your file, so your comments, formatting, and everything that isn't a type hint are preserved — you get a minimal diff, not a reformatted file. Nested generics are handled (typing.List[typing.Optional[int]] becomes list[int | None]), multi-line 'from typing import (...)' blocks are supported, and names it modernizes are dropped from your typing import automatically, with the import removed entirely if nothing is left.
Everything runs in your browser — nothing is uploaded. Because it's a targeted text transform, review the diff before committing, especially if your file has unusual formatting; the same caution applies to pyupgrade. One compatibility note: the builtin-generic and | syntaxes require Python 3.9 and 3.10+ respectively at runtime, so only modernize code that will run on those versions (annotations under from __future__ import annotations are fine on older runtimes too).
Frequently Asked Questions
Explore Other Tools
Python 2 to 3 Converter
Automatically migrate legacy version 2 code to modern version 3 syntax.
Python AST Viewer
Visualize and explore the Abstract Syntax Tree of your scripts.
Python to EXE Online
Turn a Python script into a standalone .exe online — a GitHub Actions workflow builds Windows, macOS & Linux executables on real runners. Free.
cURL to Python Converter
Paste any curl command and instantly get clean Python code for requests, httpx, or aiohttp.