typing.overload describes multiple signatures for one function to a static type checker. It helps when the return type depends on argument types or combinations and a plain union would lose that relationship.

from typing import overload

@overload
def normalizar(valor: str) -> str: ...
@overload
def normalizar(valor: bytes) -> bytes: ...

def normalizar(valor: str | bytes) -> str | bytes:
    return valor.strip().lower()

texto = normalizar("  Python ")
dados = normalizar(b"  API ")

The @overload declarations end with ... and immediately precede one concrete implementation. At runtime, the final function handles every case, so it must still validate input and match all advertised signatures.

Practical guidance

Place narrow signatures before broad ones and avoid overlaps that cannot be distinguished. Test runtime logic because a type checker cannot prove the implementation. Prefer a TypeVar when it expresses the same input-output relationship more simply; long overload sets are costly to maintain.

Review the type hints guide and run mypy against project signatures.

The official typing.overload documentation, accessed July 22, 2026, documents the API and its constraints.