スキル一覧に戻る
jsmithdenverdev

python-type-hints

by jsmithdenverdev

OpenCode configuration

0🍴 0📅 2026年1月21日
GitHubで見るManusで実行

SKILL.md


name: python-type-hints description: Type annotations, static typing with mypy, generic types, protocols license: MIT compatibility: opencode metadata: audience: python-developers focus: typing

What I do

I provide guidance on type hints and static typing in Python, including:

  • Basic type hints (list, dict, tuple, Optional, Union)
  • Type unions and intersection types (Literal, TypeGuard)
  • Generic types and TypeVar
  • Protocol types (structural subtyping)
  • Self types and recursive types
  • Callable and function types
  • mypy configuration and strict mode
  • Type narrowing and isinstance checks
  • Type stub files for third-party libraries

When to use me

Use me when:

  • Adding type hints to existing code
  • Designing type-safe APIs
  • Configuring mypy for a project
  • Working with generic types
  • Creating type guards and type predicates
  • Writing type stub files
  • Debugging type checking errors
  • Implementing protocols for duck typing
  • Designing self-referential types

Best Practices

✅ Basic Type Hints

from typing import Optional, Union, Literal
from pathlib import Path

def process_file(
    path: Path,
    encoding: Optional[str] = None,
    mode: Literal["read", "write"] = "read"
) -> Union[str, bytes]:
    """Process a file with proper type hints."""
    if mode == "read":
        return path.read_text(encoding or "utf-8")
    else:
        return path.read_bytes()

✅ Use Modern Union Syntax (Python 3.10+)

# Python 3.10+ union syntax
def process_value(value: str | int | float) -> str:
    """Process value using modern union syntax."""
    return str(value)

# Equivalent to old syntax (Python < 3.10)
from typing import Union

def process_value(value: Union[str, int, float]) -> str:
    """Process value using old union syntax."""
    return str(value)

✅ Use TypeGuard for Type Narrowing

from typing import Protocol, TypeGuard

class SupportsRead(Protocol):
    """Protocol for readable objects."""
    def read(self, size: int = -1) -> bytes: ...

def is_binary_data(obj: object) -> TypeGuard[SupportsRead]:
    """Type guard for binary data objects."""
    return isinstance(obj, (bytes, bytearray, SupportsRead))

def process_data(data: SupportsRead | str) -> bytes:
    """Process data with type narrowing."""
    if is_binary_data(data):
        return data.read()
    return data.encode()

✅ Use Protocols for Structural Subtyping

from typing import Protocol, runtime_checkable

@runtime_checkable
class Drawable(Protocol):
    """Protocol for drawable objects."""

    def draw(self) -> None: ...

def render(objects: list[Drawable]) -> None:
    """Render all drawable objects."""
    for obj in objects:
        obj.draw()

# Usage with runtime checking
class Circle:
    def draw(self) -> None:
        print("Drawing circle")

def can_draw(obj: object) -> bool:
    """Check if object is drawable."""
    return isinstance(obj, Drawable)

✅ Generic Types with TypeVar

from typing import TypeVar, Generic

T = TypeVar("T")

class Container(Generic[T]):
    """Generic container for any type."""

    def __init__(self, value: T) -> None:
        self.value = value

    def get(self) -> T:
        """Get the stored value."""
        return self.value

# Bounded TypeVar
class Animal:
    pass

class Dog(Animal):
    pass

A = TypeVar("A", bound=Animal)

def adopt(pet: A) -> A:
    """Adopt an animal."""
    return pet

# Usage
container_int = Container(42)
container_str = Container("hello")

✅ Self Types for Fluent Interfaces

from typing import Self

class Builder:
    """Builder pattern with Self type."""

    def __init__(self) -> None:
        self.items: list[str] = []

    def add_item(self, item: str) -> Self:
        """Add an item and return self for chaining."""
        self.items.append(item)
        return self

    def build(self) -> list[str]:
        """Build and return the list."""
        return self.items

# Usage
result = Builder().add_item("a").add_item("b").build()

✅ Callable Types

from typing import Callable

def apply_function(
    func: Callable[[int, int], int],
    a: int,
    b: int
) -> int:
    """Apply a function to two integers."""
    return func(a, b)

# With variable arguments
def process_data(
    processor: Callable[..., str],
    *args: object
) -> str:
    """Process data with a callable."""
    return processor(*args)

✅ Type Stubs for Third-Party Libraries

# mymodule_stubs.pyi
# Type stub file for mymodule

from typing import List, Optional

def process_items(items: List[str]) -> Optional[dict]:
    """Process items and return optional dict."""
    ...

class DataProcessor:
    """Data processor class."""
    def __init__(self, config: dict) -> None: ...
    def run(self) -> None: ...

✅ ParamSpec and Concatenate (Python 3.10+)

from typing import ParamSpec, Concatenate

P = ParamSpec("P")

def decorator(
    func: Callable[Concatenate[int, P], int]
) -> Callable[P, int]:
    """Decorator with parameter specification."""
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> int:
        return func(42, *args, **kwargs)
    return wrapper

@decorator
def multiply(x: int, y: int) -> int:
    """Multiply two numbers."""
    return x * y

Type Narrowing

✅ Use isinstance for Type Narrowing

def process(value: int | str | list[str]) -> str:
    """Process value with type narrowing."""
    if isinstance(value, int):
        return f"Number: {value}"
    elif isinstance(value, str):
        return f"String: {value}"
    else:
        # value is list[str] here
        return f"List: {', '.join(value)}"

✅ Use Literal for Precise Values

from typing import Literal

def set_status(status: Literal["pending", "active", "completed"]) -> None:
    """Set status to one of the literal values."""
    pass

# Works
set_status("active")

# Type error (mypy catches this)
set_status("invalid")

Mypy Configuration

✅ Setup mypy for Your Project

# mypy.ini or setup.cfg
[mypy]
python_version = 3.11
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
disallow_any_generics = True
check_untyped_defs = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
warn_unreachable = True
strict_equality = True

[pytest]
ignore_missing_imports = True

[tests]
no_warn_unused_ignores = True

✅ Use Type Comments for Legacy Code

# Type comments for Python 3.5-3.8 compatibility

def calculate_total(x, y):
    # type: (int, float) -> float
    """Calculate total with type comments."""
    return x + y

Common Pitfalls

❌ Don't Use Optional When Value is Required

# BAD: Optional when value is always present
def get_user_id(user_id: Optional[int]) -> int:
    if user_id is None:
        raise ValueError("user_id required")
    return user_id

# GOOD: Use non-optional type
def get_user_id(user_id: int) -> int:
    return user_id

❌ Don't Overuse Any

# BAD: Any hides type errors
def process_data(data: Any) -> Any:
    return data.process()

# GOOD: Use specific type or Protocol
def process_data(data: SupportsProcess) -> Result:
    return data.process()

❌ Don't Ignore Type Errors

# BAD: Silencing type errors without reason
def complex_function(x: int, y: str) -> dict:  # type: ignore
    return {"result": x + int(y)}

# GOOD: Fix the type error or explain the ignore
def complex_function(x: int, y: str) -> dict[str, int]:
    return {"result": x + int(y)}

Advanced Type Patterns

✅ Recursive Types

from typing import Union, TypedDict

class Node(TypedDict):
    """Recursive tree node."""
    value: int
    left: Union["Node", None]
    right: Union["Node", None]

def sum_tree(node: Union[Node, None]) -> int:
    """Sum all values in tree."""
    if node is None:
        return 0
    return node["value"] + sum_tree(node["left"]) + sum_tree(node["right"])

✅ TypedDict for Dictionary Structure

from typing import TypedDict, Required, NotRequired

class User(TypedDict):
    """User structure definition."""
    id: Required[int]
    name: Required[str]
    email: Required[str]
    age: NotRequired[int]

def process_user(user: User) -> None:
    """Process user with guaranteed structure."""
    print(f"User: {user['name']} ({user['email']})")

Type Checking Workflow

  1. Enable mypy in CI/CD
  2. Run mypy before committing (pre-commit hook)
  3. Fix type errors incrementally
  4. Use # type: ignore sparingly and document why
  5. Add stub files for untyped dependencies
  6. Keep type hints up to date when changing code
  7. Use strict mode for new code

References

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です