Types

This post is to cover a comprehensive, intuitive set of advanced typing primitives that show up in modern Python (≥3.9). These types enable:
– Type safety without runtime overhead
– Better IDE autocomplete
– Self-documenting APIs
– Generic/reusable code

To read below codes, need to know Type hints are ignored by Python’s interpreter — they exist only for static analysis, IDEs, and documentation, i.e. Python itself completely ignores all your type hints (Callable, Awaitable, list[int], etc.) and executes the code normally.

In developing or engineering a good system, the right workflow is Write code with type hints, Use Pyright or MyPy frequently, then Run your SDK, then can optionally Add type checking to CI/CD.

 This guide covers advanced typing concepts used in professional SDKs.                                                                                │ │
│ │ These types enable:                                                                                                                                  │ │
│ │ - Type safety without runtime overhead                                                                                                               │ │
│ │ - Better IDE autocomplete                                                                                                                            │ │
│ │ - Self-documenting APIs                                                                                                                              │ │
│ │ - Generic/reusable code                                                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ Author: Educational reference for SDK development                                                                                                    │ │
│ │ """                                                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ from typing import (                                                                                                                                 │ │
│ │     Callable, Awaitable, TypeVar, Generic, Protocol, Union, Optional,                                                                                │ │
│ │     Literal, TypeAlias, ParamSpec, Concatenate, TypedDict, NotRequired,                                                                              │ │
│ │     Any, cast, overload, TYPE_CHECKING                                                                                                               │ │
│ │ )                                                                                                                                                    │ │
│ │ from collections.abc import Awaitable as AbcAwaitable, Callable as AbcCallable                                                                       │ │
│ │ from dataclasses import dataclass                                                                                                                    │ │
│ │ from abc import ABC, abstractmethod                                                                                                                  │ │
│ │ import asyncio                                                                                                                                       │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 1: Callable - Function Type Signatures                                                                                                     │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Callable[<parameter_types>, <return_type>]                                                                                                         │ │
│ │ # Describes the signature of a function/method                                                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Example 1: Simple function                                                                                                                         │ │
│ │ def greet(name: str) -> str:                                                                                                                         │ │
│ │     return f"Hello, {name}"                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ # Type hint: "a function that takes str and returns str"                                                                                             │ │
│ │ SimpleFunction: TypeAlias = Callable[[str], str]                                                                                                     │ │
│ │ my_func: SimpleFunction = greet  # ✓ Valid                                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 2: Multiple parameters                                                                                                                     │ │
│ │ def add(a: int, b: int) -> int:                                                                                                                      │ │
│ │     return a + b                                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ BinaryOperation: TypeAlias = Callable[[int, int], int]                                                                                               │ │
│ │ operation: BinaryOperation = add  # ✓ Valid                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 3: No parameters                                                                                                                           │ │
│ │ def get_timestamp() -> float:                                                                                                                        │ │
│ │     import time                                                                                                                                      │ │
│ │     return time.time()                                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │ NoArgsFunction: TypeAlias = Callable[[], float]                                                                                                      │ │
│ │ timestamp_fn: NoArgsFunction = get_timestamp  # ✓ Valid                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 4: Callback pattern (common in SDKs)                                                                                                       │ │
│ │ @dataclass                                                                                                                                           │ │
│ │ class Event:                                                                                                                                         │ │
│ │     name: str                                                                                                                                        │ │
│ │     data: dict                                                                                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ EventHandler: TypeAlias = Callable[[Event], None]                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │ def on_calculation(event: Event) -> None:                                                                                                            │ │
│ │     print(f"Calculation event: {event.name}")                                                                                                        │ │
│ │                                                                                                                                                      │ │
│ │ handlers: list[EventHandler] = [on_calculation]                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Usage:                                                                                                                                             │ │
│ │ event = Event(name="add", data={"result": 42})                                                                                                       │ │
│ │ for handler in handlers:                                                                                                                             │ │
│ │     handler(event)  # Type-safe callback                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 2: Awaitable - Async/Promise Types                                                                                                         │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Awaitable[T] - Something that can be awaited (returns T)                                                                                           │ │
│ │ # Includes: coroutines, Tasks, Futures                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │ # Example 1: Simple async function                                                                                                                   │ │
│ │ async def fetch_data() -> str:                                                                                                                       │ │
│ │     await asyncio.sleep(0.1)                                                                                                                         │ │
│ │     return "data"      
 # Example 2: Async callback pattern (like calculator SDK hooks)                                                                                      │ │
│ │ @dataclass                                                                                                                                           │ │
│ │ class HookContext:                                                                                                                                   │ │
│ │     operation: str                                                                                                                                   │ │
│ │     params: dict                                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ @dataclass                                                                                                                                           │ │
│ │ class HookResult:                                                                                                                                    │ │
│ │     allow: bool                                                                                                                                      │ │
│ │     message: str = ""                                                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ # AsyncHook: takes context, returns awaitable result                                                                                                 │ │
│ │ AsyncHook: TypeAlias = Callable[[HookContext], Awaitable[HookResult]]                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ async def validate_input(ctx: HookContext) -> HookResult:                                                                                            │ │
│ │     """Example async hook"""                                                                                                                         │ │
│ │     if ctx.operation == "divide" and ctx.params.get("b") == 0:                                                                                       │ │
│ │         return HookResult(allow=False, message="Cannot divide by zero")                                                                              │ │
│ │     return HookResult(allow=True)                                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │ # Usage:                                                                                                                                             │ │
│ │ my_hook: AsyncHook = validate_input  # ✓ Type matches                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ async def run_hooks(hook: AsyncHook, context: HookContext):                                                                                          │ │
│ │     result = await hook(context)  # ✓ Can await the result                                                                                           │ │
│ │     print(f"Hook result: {result.allow}")                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 3: TypeVar - Generic Type Parameters                                                                                                       │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # TypeVar creates placeholders for types that will be determined later                                                                               │ │
│ │ # Used for generic functions/classes                                                                                                                 │ │
│ │                                                                                                                                                      │ │
│ │ T = TypeVar('T')  # Unconstrained - can be any type                                                                                                  │ │
│ │ TNumber = TypeVar('TNumber', int, float)  # Constrained to int or float                                                                              │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 1: Generic function                                                                                                                        │ │
│ │ def first_element(items: list[T]) -> T:                                                                                                              │ │
│ │     """Returns first element, preserving type"""                                                                                                     │ │
│ │     return items[0]                                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ # Type inference works:                                                                                                                              │ │
│ │ nums: list[int] = [1, 2, 3]                                                                                                                          │ │
│ │ result1: int = first_element(nums)  # ✓ Inferred as int                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ names: list[str] = ["Alice", "Bob"]                                                                                                                  │ │
│ │ result2: str = first_element(names)  # ✓ Inferred as str                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 2: Generic class                                                                                                                           │ │
│ │ class Box(Generic[T]):                                                                                                                               │ │
│ │     """A container that holds any type"""                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │     def __init__(self, value: T):                                                                                                                    │ │
│ │         self.value = value                                                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │     def get(self) -> T:                                                                                                                              │ │
│ │         return self.value                                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │ int_box: Box[int] = Box(42)                                                                                                                          │ │
│ │ x: int = int_box.get()  # ✓ Type checker knows it's int                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ str_box: Box[str] = Box("hello")                                                                                                                     │ │
│ │ y: str = str_box.get()  # ✓ Type checker knows it's str                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 3: Bounded TypeVar (like OpenAI SDK)                                                                                                       │ │
│ │ class Agent:                                                                                                                                         │ │
│ │     name: str                                                                                                                                        │ │
│ │                                                                                                                                                      │ │
│ │ class SpecializedAgent(Agent):                                                                                                                       │ │
│ │     specialization: str                                                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ TAgent = TypeVar('TAgent', bound=Agent)  # Must be Agent or subclass                                                                                 │ │
│ │                                                                                                                                                      │ │
│ │ def process_agent(agent: TAgent) -> TAgent:                                                                                                          │ │
│ │     """Returns same type as input"""                                                                                                                 │ │
│ │     print(agent.name)  # ✓ Type checker knows 'name' exists                                                                                          │ │
│ │     return agent                                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ # Works with subclasses:                                                                                                                             │ │
│ │ special = SpecializedAgent()                                                                                                                         │ │
│ │ result: SpecializedAgent = process_agent(special)  # ✓ Preserves type                                                                                │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 4: Protocol - Structural Subtyping (Duck Typing)                                                                                           │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Protocol defines interface without inheritance                                                                                                     │ │
│ │ # "If it walks like a duck and quacks like a duck..."                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ class Drawable(Protocol):                                                                                                                            │ │
│ │     """Anything with a draw() method"""                                                                                                              │ │
│ │     def draw(self) -> str:                                                                                                                           │ │
│ │         ...                                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ class Circle:                                                                                                                                        │ │
│ │     def draw(self) -> str:                                                                                                                           │ │
│ │         return "○"                                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ class Square:                                                                                                                                        │ │
│ │     def draw(self) -> str:                                                                                                                           │ │
│ │         return "□"                                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ def render(shape: Drawable) -> str:                                                                                                                  │ │
│ │     """Accepts ANY object with draw() method"""                                                                                                      │ │
│ │     return shape.draw()                                                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ # Both work without inheriting from Drawable:                                                                                                        │ │
│ │ print(render(Circle()))  # ✓ Works                                                                                                                   │ │
│ │ print(render(Square()))  # ✓ Works                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: Session Protocol (like OpenAI SDK)                                                                                                        │ │
│ │ class Session(Protocol):                                                                                                                             │ │
│ │     """Defines session interface"""                                                                                                                  │ │
│ │     async def get_items(self, limit: int | None = None) -> list[dict]:                                                                               │ │
│ │         ...                                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │     async def add_items(self, items: list[dict]) -> None:                                                                                            │ │
│ │         ...                                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ class MemorySession:                                                                                                                                 │ │
│ │     """Implements Session protocol without inheriting"""                                                                                             │ │
│ │     def __init__(self):                                                                                                                              │ │
│ │         self.items: list[dict] = []                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │     async def get_items(self, limit: int | None = None) -> list[dict]:                                                                               │ │
│ │         return self.items[:limit] if limit else self.items                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │     async def add_items(self, items: list[dict]) -> None:                                                                                            │ │
│ │         self.items.extend(items)                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ async def use_session(session: Session):                                                                                                             │ │
│ │     """Works with ANY class matching Session protocol"""                                                                                             │ │
│ │     await session.add_items([{"msg": "hello"}])                                                                                                      │ │
│ │     items = await session.get_items()                                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ # Works even though MemorySession doesn't inherit from Session:                                                                                      │ │
│ │ # await use_session(MemorySession())  # ✓ Valid                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 5: Union and Optional                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Union[A, B] - "can be A or B"                                                                                                                      │ │
│ │ # Optional[T] - shorthand for Union[T, None]                                                                                                         │ │
│ │                                                                                                                                                      │ │
│ │ # Example 1: Union for multiple return types                                                                                                         │ │
│ │ def parse_number(value: str) -> int | float | None:                                                                                                  │ │
│ │     """Returns int, float, or None"""                                                                                                                │ │
│ │     try:                                                                                                                                             │ │
│ │         if '.' in value:                                                                                                                             │ │
│ │             return float(value)                                                                                                                      │ │
│ │         return int(value)                                                                                                                            │ │
│ │     except ValueError:                                                                                                                               │ │
│ │         return None                                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ result: int | float | None = parse_number("42")                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 2: Optional for nullable values                                                                                                            │ │
│ │ class User:                                                                                                                                          │ │
│ │     def __init__(self, name: str, email: str | None = None):                                                                                         │ │
│ │         self.name = name                                                                                                                             │ │
│ │         self.email = email  # Can be None                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │ def send_email(user: User) -> bool:                                                                                                                  │ │
│ │     if user.email is None:                                                                                                                           │ │
│ │         return False                                                                                                                                 │ │
│ │     # Type narrowing: after check, type checker knows email is str                                                                                   │ │
│ │     print(f"Sending to {user.email}")                                                                                                                │ │
│ │     return True                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example 3: Union with type guard                                                                                                                   │ │
│ │ def process_value(value: int | str) -> str:                                                                                                          │ │
│ │     """Process different types differently"""                                                                                                        │ │
│ │     if isinstance(value, int):                                                                                                                       │ │
│ │         # Type narrowed to int                                                                                                                       │ │
│ │         return f"Number: {value * 2}"                                                                                                                │ │
│ │     else:                                                                                                                                            │ │
│ │         # Type narrowed to str                                                                                                                       │ │
│ │         return f"Text: {value.upper()}"                                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 6: Literal - Exact Value Types                                                                                                             │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Literal restricts to specific values                                                                                                               │ │
│ │ # Common for enums/modes without creating enum class                                                                                                 │ │
│ │                                                                                                                                                      │ │
│ │ Mode = Literal["read", "write", "append"]                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │ def open_file(path: str, mode: Mode) -> None:                                                                                                        │ │
│ │     """mode must be exactly 'read', 'write', or 'append'"""                                                                                          │ │
│ │     print(f"Opening {path} in {mode} mode")                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ open_file("data.txt", "read")    # ✓ Valid                                                                                                           │ │
│ │ # open_file("data.txt", "delete")  # ✗ Type error                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: Calculator SDK style                                                                                                                      │ │
│ │ OperationType = Literal["add", "subtract", "multiply", "divide"]                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ def calculate(op: OperationType, a: float, b: float) -> float:                                                                                       │ │
│ │     if op == "add":                                                                                                                                  │ │
│ │         return a + b                                                                                                                                 │ │
│ │     elif op == "subtract":                                                                                                                           │ │
│ │         return a - b                                                                                                                                 │ │
│ │     elif op == "multiply":                                                                                                                           │ │
│ │         return a * b                                                                                                                                 │ │
│ │     else:  # Type checker knows op must be "divide" here                                                                                             │ │
│ │         return a / b                                                                                                                                 │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: Result type discriminator                                                                                                                 │ │
│ │ ResultType = Literal["success", "error"]                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │ @dataclass                                                                                                                                           │ │
│ │ class Result:                                                                                                                                        │ │
│ │     type: ResultType                                                                                                                                 │ │
│ │     value: Any = None                                                                                                                                │ │
│ │     error: str | None = None                                                                                                                         │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 7: TypeAlias - Readable Type Names                                                                                                         │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Makes complex types readable and reusable                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ # Before: Messy                                                                                                                                      │ │
│ │ def process_handlers(                                                                                                                                │ │
│ │     handlers: dict[str, list[Callable[[dict[str, Any]], Awaitable[bool]]]]                                                                           │ │
│ │ ) -> None:                                                                                                                                           │ │
│ │     pass                                                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │ # After: Clean                                                                                                                                       │ │
│ │ EventCallback: TypeAlias = Callable[[dict[str, Any]], Awaitable[bool]]                                                                               │ │
│ │ HandlerRegistry: TypeAlias = dict[str, list[EventCallback]]                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ def process_handlers_clean(handlers: HandlerRegistry) -> None:                                                                                       │ │
│ │     pass                                                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: Complex nested types                                                                                                                      │ │
│ │ JsonValue: TypeAlias = str | int | float | bool | None | list['JsonValue'] | dict[str, 'JsonValue']                                                  │ │
│ │                                                                                                                                                      │ │
│ │ def parse_json(data: str) -> JsonValue:                                                                                                              │ │
│ │     import json                                                                                                                                      │ │
│ │     return json.loads(data)                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 8: ParamSpec - Preserve Function Signatures                                                                                                │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # ParamSpec preserves exact parameter signature when wrapping functions                                                                              │ │
│ │ # Used for decorators                                                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ P = ParamSpec('P')                                                                                                                                   │ │
│ │ R = TypeVar('R')                                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ def log_calls(func: Callable[P, R]) -> Callable[P, R]:                                                                                               │ │
│ │     """Decorator that preserves exact function signature"""                                                                                          │ │
│ │     def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:                                                                                             │ │
│ │         print(f"Calling {func.__name__}")                                                                                                            │ │
│ │         return func(*args, **kwargs)                                                                                                                 │ │
│ │     return wrapper                                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ @log_calls                                                                                                                                           │ │
│ │ def add_numbers(a: int, b: int) -> int:                                                                                                              │ │
│ │     return a + b                                                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │ # Type checker knows exact signature is preserved:                                                                                                   │ │
│ │ result: int = add_numbers(1, 2)  # ✓ Valid                                                                                                           │ │
│ │ # result = add_numbers("1", "2")  # ✗ Type error                                                                                                     │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 9: TypedDict - Structured Dictionaries                                                                                                     │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # TypedDict provides type hints for dictionary keys/values                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │ class UserDict(TypedDict):                                                                                                                           │ │
│ │     """Typed dictionary for user data"""                                                                                                             │ │
│ │     id: int                                                                                                                                          │ │
│ │     name: str                                                                                                                                        │ │
│ │     email: str                                                                                                                                       │ │
│ │     age: NotRequired[int]  # Optional key (Python 3.11+)                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │ def create_user(user: UserDict) -> None:                                                                                                             │ │
│ │     print(f"User: {user['name']}")  # ✓ Type checker knows 'name' exists                                                                             │ │
│ │     # print(user['invalid'])  # ✗ Type error                                                                                                         │ │
│ │                                                                                                                                                      │ │
│ │ user: UserDict = {                                                                                                                                   │ │
│ │     "id": 1,                                                                                                                                         │ │
│ │     "name": "Alice",                                                                                                                                 │ │
│ │     "email": "alice@example.com"                                                                                                                     │ │
│ │     # age is optional                                                                                                                                │ │
│ │ }                                                                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: API Response                                                                                                                              │ │
│ │ class ApiResponse(TypedDict):                                                                                                                        │ │
│ │     status: Literal["success", "error"]                                                                                                              │ │
│ │     data: dict[str, Any]                                                                                                                             │ │
│ │     message: NotRequired[str]                                                                                                                        │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 10: Overload - Multiple Function Signatures                                                                                                │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # @overload declares different signatures for same function                                                                                          │ │
│ │ # Helps type checker understand complex behaviors                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │ @overload                                                                                                                                            │ │
│ │ def get_value(key: str) -> str: ...                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ @overload                                                                                                                                            │ │
│ │ def get_value(key: str, default: int) -> int: ...                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │ def get_value(key: str, default: str | int = "") -> str | int:                                                                                       │ │
│ │     """Returns string or int depending on default type"""                                                                                            │ │
│ │     # Implementation                                                                                                                                 │ │
│ │     if isinstance(default, int):                                                                                                                     │ │
│ │         return default                                                                                                                               │ │
│ │     return default                                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ # Type checker infers correctly:                                                                                                                     │ │
│ │ v1: str = get_value("key")          # ✓ Returns str                                                                                                  │ │
│ │ v2: int = get_value("key", 42)      # ✓ Returns int                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Example: OpenAI SDK style handoff overloads                                                                                                        │ │
│ │ class Agent:                                                                                                                                         │ │
│ │     name: str                                                                                                                                        │ │
│ │                                                                                                                                                      │ │
│ │ @overload                                                                                                                                            │ │
│ │ def handoff(agent: Agent) -> None: ...                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │ @overload                                                                                                                                            │ │
│ │ def handoff(agent: Agent, data: dict[str, Any]) -> None: ...                                                                                         │ │
│ │                                                                                                                                                      │ │
│ │ def handoff(agent: Agent, data: dict[str, Any] | None = None) -> None:                                                                               │ │
│ │     """Handle agent handoff with optional data"""                                                                                                    │ │
│ │     if data:                                                                                                                                         │ │
│ │         print(f"Handoff to {agent.name} with data")                                                                                                  │ │
│ │     else:                                                                                                                                            │ │
│ │         print(f"Handoff to {agent.name}")                                                                                                            │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 11: TYPE_CHECKING - Import-Time Only Types                                                                                                 │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Avoid circular imports by importing types only during type checking                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ if TYPE_CHECKING:                                                                                                                                    │ │
│ │     # These imports only happen when type checker runs                                                                                               │ │
│ │     # Not imported at runtime                                                                                                                        │ │
│ │     from typing import Never                                                                                                                         │ │
│ │     from collections.abc import Sequence                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │ # Usage: forward references without runtime overhead                                                                                                 │ │
│ │ def process_items(items: 'Sequence[int]') -> None:                                                                                                   │ │
│ │     """Quotes prevent runtime evaluation"""                                                                                                          │ │
│ │     pass                                                                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 12: cast - Type Assertion                                                                                                                  │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Tell type checker "trust me, this is this type"                                                                                                    │ │
│ │ # Use sparingly - no runtime checking                                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │ def get_user_data() -> dict[str, Any]:                                                                                                               │ │
│ │     return {"name": "Alice", "age": 30}                                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │ # Type checker doesn't know the structure                                                                                                            │ │
│ │ data = get_user_data()                                                                                                                               │ │
│ │ # name = data["name"].upper()  # ✗ Type checker unsure                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │ # With cast:                                                                                                                                         │ │
│ │ typed_data = cast(UserDict, data)                                                                                                                    │ │
│ │ name = typed_data["name"].upper()  # ✓ Type checker trusts you                                                                                       │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SECTION 13: Generic Protocols - Advanced Pattern                                                                                                   │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ # Combine Protocol + Generic for flexible interfaces                                                                                                 │ │
│ │                                                                                                                                                      │ │
│ │ T_co = TypeVar('T_co', covariant=True)  # Covariant - allows subtype returns                                                                         │ │
│ │                                                                                                                                                      │ │
│ │ class Container(Protocol, Generic[T_co]):                                                                                                            │ │
│ │     """Generic container protocol"""                                                                                                                 │ │
│ │     def get(self) -> T_co:                                                                                                                           │ │
│ │         ...                                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ class StringContainer:                                                                                                                               │ │
│ │     def get(self) -> str:                                                                                                                            │ │
│ │         return "hello"                                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │ def use_container(container: Container[str]) -> str:                                                                                                 │ │
│ │     return container.get()                                                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │ # Works without inheritance:                                                                                                                         │ │
│ │ use_container(StringContainer())  # ✓ Valid                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # PRACTICAL EXAMPLE: Complete SDK Hook System                                                                                                        │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ class HookContextData(TypedDict):                                                                                                                    │ │
│ │     """Typed dict for hook context"""                                                                                                                │ │
│ │     operation: str                                                                                                                                   │ │
│ │     inputs: dict[str, float]                                                                                                                         │ │
│ │     session_id: str                                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ class HookResultData(TypedDict):                                                                                                                     │ │
│ │     """Typed dict for hook result"""                                                                                                                 │ │
│ │     type: Literal["allow", "deny", "modify"]                                                                                                         │ │
│ │     message: NotRequired[str]                                                                                                                        │ │
│ │     modified_inputs: NotRequired[dict[str, float]]                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ # Generic hook with context type parameter                                                                                                           │ │
│ │ TContext = TypeVar('TContext')                                                                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ class Hook(Protocol[TContext]):                                                                                                                      │ │
│ │     """Generic hook protocol"""                                                                                                                      │ │
│ │     async def __call__(self, context: TContext) -> HookResultData:                                                                                   │ │
│ │         ...                                                                                                                                          │ │
│ │                                                                                                                                                      │ │
│ │ # Specific hook types                                                                                                                                │ │
│ │ CalculatorHook: TypeAlias = Callable[[HookContextData], Awaitable[HookResultData]]                                                                   │ │
│ │                                                                                                                                                      │ │
│ │ class HookRegistry:                                                                                                                                  │ │
│ │     """Type-safe hook registry"""                                                                                                                    │ │
│ │                                                                                                                                                      │ │
│ │     def __init__(self):                                                                                                                              │ │
│ │         self.hooks: dict[str, list[CalculatorHook]] = {}                                                                                             │ │
│ │                                                                                                                                                      │ │
│ │     def register(self, event: str, hook: CalculatorHook) -> None:                                                                                    │ │
│ │         """Register a hook for an event"""                                                                                                           │ │
│ │         if event not in self.hooks:                                                                                                                  │ │
│ │             self.hooks[event] = []                                                                                                                   │ │
│ │         self.hooks[event].append(hook)                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │     async def execute(self, event: str, context: HookContextData) -> list[HookResultData]:                                                           │ │
│ │         """Execute all hooks for an event"""                                                                                                         │ │
│ │         results: list[HookResultData] = []                                                                                                           │ │
│ │                                                                                                                                                      │ │
│ │         for hook in self.hooks.get(event, []):                                                                                                       │ │
│ │             result = await hook(context)                                                                                                             │ │
│ │             results.append(result)                                                                                                                   │ │
│ │                                                                                                                                                      │ │
│ │         return results                                                                                                                               │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # Usage example:                                                                                                                                     │ │
│ │ async def validation_hook(ctx: HookContextData) -> HookResultData:                                                                                   │ │
│ │     """Validate inputs"""                                                                                                                            │ │
│ │     if ctx["operation"] == "divide" and ctx["inputs"].get("b") == 0:                                                                                 │ │
│ │         return {"type": "deny", "message": "Division by zero"}                                                                                       │ │
│ │     return {"type": "allow"}                                                                                                                         │ │
│ │                                                                                                                                                      │ │
│ │ async def main():                                                                                                                                    │ │
│ │     registry = HookRegistry()                                                                                                                        │ │
│ │     registry.register("pre_calculate", validation_hook)                                                                                              │ │
│ │                                                                                                                                                      │ │
│ │     context: HookContextData = {                                                                                                                     │ │
│ │         "operation": "divide",                                                                                                                       │ │
│ │         "inputs": {"a": 10.0, "b": 0.0},                                                                                                             │ │
│ │         "session_id": "test"                                                                                                                         │ │
│ │     }                                                                                                                                                │ │
│ │                                                                                                                                                      │ │
│ │     results = await registry.execute("pre_calculate", context)                                                                                       │ │
│ │     for result in results:                                                                                                                           │ │
│ │         print(f"Hook result: {result['type']}")                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │                                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │ # SUMMARY TABLE                                                                                                                                      │ │
│ │ # ============================================================================                                                                       │ │
│ │                                                                                                                                                      │ │
│ │ """                                                                                                                                                  │ │
│ │ ┌─────────────────┬──────────────────────────────────────┬────────────────────────┐                                                                  │ │
│ │ │ Type            │ Purpose                              │ Example                │                                                                  │ │
│ │ ├─────────────────┼──────────────────────────────────────┼────────────────────────┤                                                                  │ │
│ │ │ Callable        │ Function signature                   │ Callable[[int], str]   │                                                                  │ │
│ │ │ Awaitable       │ Async return type                    │ Awaitable[int]         │                                                                  │ │
│ │ │ TypeVar         │ Generic type parameter               │ T = TypeVar('T')       │                                                                  │ │
│ │ │ Generic         │ Create generic classes               │ class Box(Generic[T])  │                                                                  │ │
│ │ │ Protocol        │ Structural interface (duck typing)   │ class Drawable(Proto.) │                                                                  │ │
│ │ │ Union           │ Multiple possible types              │ int | str              │                                                                  │ │
│ │ │ Optional        │ Type or None                         │ Optional[str]          │                                                                  │ │
│ │ │ Literal         │ Exact value constraint               │ Literal["a", "b"]      │                                                                  │ │
│ │ │ TypeAlias       │ Readable type names                  │ UserId: TypeAlias=int  │                                                                  │ │
│ │ │ ParamSpec       │ Preserve function signatures         │ P = ParamSpec('P')     │                                                                  │ │
│ │ │ TypedDict       │ Typed dictionary structure           │ class User(TypedDict)  │                                                                  │ │
│ │ │ overload        │ Multiple function signatures         │ @overload def f()      │                                                                  │ │
│ │ │ TYPE_CHECKING   │ Import only during type checking     │ if TYPE_CHECKING:      │                                                                  │ │
│ │ │ cast            │ Type assertion                       │ cast(str, value)       │                                                                  │ │
│ │ │ NotRequired     │ Optional TypedDict key               │ age: NotRequired[int]  │                                                                  │ │
│ │ └─────────────────┴──────────────────────────────────────┴────────────────────────┘                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ Common Patterns in Professional SDKs:                                                                                                                │ │
│ │ 1. Callback hooks: Callable[[Context], Awaitable[Result]]                                                                                            │ │
│ │ 2. Generic containers: class Container(Generic[T])                                                                                                   │ │
│ │ 3. Session protocols: class Session(Protocol)                                                                                                        │ │
│ │ 4. Type aliases for complex types                                                                                                                    │ │
│ │ 5. TypedDict for API responses/configs                                                                                                               │ │
│ │ 6. Literal for mode/enum values                                                                                                                      │ │
│ │ 7. Union for multiple return types                                                                                                                   │ │
│ │ """                                                                                                                                                  │ │
│ │                                                                                                                                                      │ │
│ │ if __name__ == "__main__":                                                                                                                           │ │
│ │     print(__doc__)                                                                                                                                   │ │
│ │     print("\nThis file demonstrates advanced Python typing concepts.")                                                                               │ │
│ │     print("Run with a type checker (mypy, pyright) to see type safety in action.")                                                                   │ │
│ │                                                                                                                                                      │ │
│ │     # Run async examples                                                                                                                             │ │
│ │     asyncio.run(main())                                                                                                                              │ │
│ │                                                                                                                       

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.