DEV Community

郑沛沛
郑沛沛

Posted on

Stop Writing Python Without Type Hints — Here's How to Start

Type hints make Python code self-documenting, catch bugs before runtime, and supercharge your IDE. Here's a practical guide to adopting them incrementally.

The Basics

def greet(name: str) -> str:
    return f"Hello, {name}"

def add(a: int, b: int) -> int:
    return a + b

# Variables
age: int = 25
names: list[str] = ["Alice", "Bob"]
config: dict[str, int] = {"timeout": 30, "retries": 3}
Enter fullscreen mode Exit fullscreen mode

Optional and Union Types

from typing import Optional

# Python 3.10+
def find_user(user_id: int) -> dict | None:
    if user_id in db:
        return db[user_id]
    return None

# Pre-3.10
def find_user(user_id: int) -> Optional[dict]:
    ...
Enter fullscreen mode Exit fullscreen mode

Collections

# Python 3.9+ — use built-in types
def process(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

# Tuples with specific types
def get_coords() -> tuple[float, float]:
    return (40.7128, -74.0060)

# Sets
def unique_words(text: str) -> set[str]:
    return set(text.split())
Enter fullscreen mode Exit fullscreen mode

TypedDict for Structured Dicts

from typing import TypedDict

class UserProfile(TypedDict):
    name: str
    email: str
    age: int
    is_active: bool

def create_user(data: UserProfile) -> None:
    # IDE knows data["name"] is str, data["age"] is int
    print(f"Creating user {data['name']}")

create_user({"name": "Alice", "email": "alice@example.com", "age": 30, "is_active": True})
Enter fullscreen mode Exit fullscreen mode

Callable Types

from typing import Callable

def apply_operation(
    values: list[int],
    operation: Callable[[int], int]
) -> list[int]:
    return [operation(v) for v in values]

result = apply_operation([1, 2, 3], lambda x: x * 2)
Enter fullscreen mode Exit fullscreen mode

Generics

from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T | None:
    return items[0] if items else None

# Python 3.12+ syntax
def first[T](items: list[T]) -> T | None:
    return items[0] if items else None
Enter fullscreen mode Exit fullscreen mode

Dataclasses + Type Hints

from dataclasses import dataclass

@dataclass
class Order:
    id: int
    product: str
    quantity: int
    price: float
    shipped: bool = False

    @property
    def total(self) -> float:
        return self.quantity * self.price

order = Order(id=1, product="Widget", quantity=5, price=9.99)
print(order.total)  # 49.95
Enter fullscreen mode Exit fullscreen mode

Running mypy

pip install mypy
mypy your_script.py
Enter fullscreen mode Exit fullscreen mode
# mypy catches this:
def double(x: int) -> int:
    return x * 2

double("hello")  # error: Argument 1 has incompatible type "str"; expected "int"
Enter fullscreen mode Exit fullscreen mode

Gradual Adoption Strategy

  1. Start with function signatures (parameters + return types)
  2. Add types to dataclasses and TypedDicts
  3. Use mypy --strict on new modules
  4. Add # type: ignore sparingly for tricky third-party code

Key Takeaways

  • Type hints are optional but incredibly valuable
  • Start with function signatures — biggest bang for buck
  • Use TypedDict for dictionary structures
  • Run mypy in CI to catch type errors early
  • Python 3.10+ has the cleanest syntax (X | Y instead of Union[X, Y])

Type hints don't slow Python down — they're stripped at runtime. But they make your code dramatically easier to read, refactor, and maintain.

🚀 Level up your AI workflow! Check out my AI Developer Mega Prompt Pack — 80 battle-tested prompts for developers. $9.99

Top comments (0)