devnotes.

Type Hints Basics

Beyond simple types (int, str), Python's typing system covers optional values, unions of multiple types, and callables — all without affecting runtime behavior.

from typing import Optional, Union, Callable

def find_user(id: int) -> Optional[str]:      # Optional[str] means "str or None"
    return "Rahim" if id == 1 else None

def process(value: Union[int, str]) -> str:    # accepts either an int or a str
    return str(value)

# Python 3.10+ shorthand for both of the above — preferred in new code:
def find_user_new(id: int) -> str | None:        # | replaces Union[..., None]/Optional
    return "Rahim" if id == 1 else None

def process_new(value: int | str) -> str:
    return str(value)

def apply(func: Callable[[int, int], int], a: int, b: int) -> int:  # func's own signature
    return func(a, b)

apply(lambda x, y: x + y, 3, 4)   # 7

Optional[X] is shorthand for Union[X, None] — "a value of type X, or None" — and is one of the most common hints in real code, since so many functions can legitimately return "nothing found." Union[X, Y] means "either X or Y."

Python 3.10 introduced the X | Y syntax as a cleaner, built-in alternative to Union[X, Y] (and X | None in place of Optional[X]) — no import needed, and it's now the preferred style in modern code, with the older typing.Union/typing.Optional forms mostly seen in code targeting older Python versions.

Callable[[ArgType1, ArgType2], ReturnType] describes a function's own signature as a type — useful for parameters, like apply above, that expect to receive another function and want to document what that function's signature should look like.

Type Hints Basics: Optional, Union, and Callable | DevNotes