AI agent skill
Python Type Safety
Python type safety with type hints, generics, protocols, and strict type checking. Use when adding type annotations, implementing generic classes, defining structural interfaces, or configuring mypy/pyright.
·
When to use this skill
Use Python Type Safety when an AI agent needs a reusable SKILL.md workflow for this job: Python type safety with type hints, generics, protocols, and strict type checking. Use when adding type annotations, implementing generic classes, defining structural interfaces, or configuring mypy/pyright.
When not to use it
Skip Python Type Safety when the task is outside the coding category, or when a more specific skill in this directory already covers the same workflow with clearer triggers.
How to install
- Personal install: create ~/.claude/skills/python-type-safety/SKILL.md (and any bundled scripts) so Claude Code, Claude Desktop, and compatible agents can load it in every project.
- Project install: commit the same folder at .claude/skills/python-type-safety/ so teammates get the skill with the repo.
- Restart the agent session after copying files so it re-scans the skills directory, then ask for the task in words that match the skill description.
What this skill does
# Python Type Safety
Leverage Python's type system to catch errors at static analysis time. Type annotations serve as enforced documentation that tooling validates automatically.
## When to Use This Skill
- Adding type hints to existing code - Creating generic, reusable classes - Defining structural interfaces with protocols - Configuring mypy or pyright for strict checking - Understanding type narrowing and guards - Building type-safe APIs and libraries
## Core Concepts
### 1. Type Annotations
Declare expected types for function parameters, return values, and variables.
### 2. Generics
Write reusable code that preserves type information across different types.
### 3. Protocols
Define structural interfaces without inheritance (duck typing with type safety).
### 4. Type Narrowing
Use guards and conditionals to narrow types within code blocks.
## Quick Start
```python def get_user(user_id: str) -> User | None: """Return type makes 'might not exist' explicit.""" ...
# Type checker enforces handling None case user = get_user("123") if user is None: raise UserNotFoundError("123") print(user.name) # Type checker knows user is User here ```
## Fundamental Patterns
### Pattern 1: Annotate All Public Signatures
Every public function, method, and class should have type annotations.
```python def get_user(user_id: str) -> User: """Retrieve user by ID.""" ...
def process_batch( items: list[Item], max_workers: int = 4, ) -> BatchResult[ProcessedItem]: """Process items concurrently.""" ...
class UserRepository: def __init__(self, db: Database) -> None: self._db = db
async def find_by_id(self, user_id: str) -> User | None: """Return User if found, None otherwise.""" ...
async def find_by_email(self, email: str) -> User | None: ...
async def save(self, user: User) -> User: """Save and return user with generated ID.""" ... ```
Use `mypy --strict` or `pyright` in CI to catch type errors early. For existing projects, enable strict mode incrementally using per-module overrides.
### Pattern 2: Use Modern Union Syntax
Python 3.10+ provides cleaner union syntax.
```python # Preferred (3.10+) def find_user(user_id: str) -> User | None: ...
def parse_value(v: str) -> int | float | str: ...
# Older style (still valid, needed for 3.9) from typing import Optional, Union
def find_user(user_id: str) -> Optional[User]: ... ```
### Pattern 3: Type Narrowing with Guards
Use conditionals to narrow types for the type checker.
```python def process_user(user_id: str) -> UserData: user = find_user(user_id)
if user is None: raise UserNotFoundError(f"User {user_id} not found")
# Type checker knows user is User here, not User | None return UserData( name=user.name, email=user.email, )
def process_items(items: list[Item | None]) -> list[ProcessedItem]: # Filter and narrow types valid_items = [item for item in items if item is not None] # valid_items is now list[Item] return [process(item) for item in valid_items] ```
### Pattern 4: Generic Classes
Create type-safe reusable containers.
```python from typing import TypeVar, Generic
T = TypeVar("T") E = TypeVar("E", bound=Exception)
class Result(Generic[T, E]): """Represents either a success value or an error."""
def __init__( self, value: T | None = None, error: E | None = None, ) -> None: if (value is None) == (error is None): raise ValueError("Exactly one of value or error must be set") self._value = value self._error = error
@property def is_success(self) -> bool: return self._error is None
@property def is_failure(self) -> bool: return self._error is not None
def unwrap(self) -> T: """Get value or raise the error.""" if self._error is not None: raise self._error return self._value # type: ignore[return-value]
def unwrap_or(self, default: T) -> T: """Get value or return default.""" if self._error is not None: return default return self._value # type: ignore[return-value]
# Usage preserves types def parse_config(path: str) -> Result[Config, ConfigError]: try: return Result(value=Config.from_file(path)) except ConfigError as e: return Result(error=e)
result = parse_config("config.yaml") if result.is_success: config = result.unwrap() # Type: Config ```
## Detailed worked examples and patterns
Detailed sections (starting with `## Advanced Patterns`) live in `references/details.md`. Read that file when the navigation summary above is insufficient.
## Best Practices Summary
1. **Annotate all public APIs** - Functions, methods, class attributes 2. **Use `T | None`** - Modern union syntax over `Optional[T]` 3. **Run strict type checking** - `mypy --strict` in CI 4. **Use generics** - Preserve type info in reusable code 5. **Define protocols** - Structural typing for interfaces 6. **Narrow types** - Use guards to help the type checker 7. **Bound type vars** - Restrict generics to meaningful types 8. **Create type aliases** - Meaningful names for complex types 9. **Minimize `Any`** - Use specific types or generics. `Any` is acceptable for truly dynamic data or when interfacing with untyped third-party code 10. **Document with types** - Types are enforceable documentation
Intended uses
- Adding type hints to existing code
- Creating generic, reusable classes
- Defining structural interfaces with protocols
- Configuring mypy or pyright for strict checking
- Understanding type narrowing and guards
- Building type-safe APIs and libraries
Related skills
Related skills in this directory, for comparison before you install another skill.
coding
Act as a Patient, Non-Technical Android Studio Guide
A reusable prompt for asking an AI assistant to work as Act as a Patient, Non-Technical Android Studio Guide.
coding
Add Ave Record
The main workflow for this repo. Adds one new AVE record end to end.
coding
Add Backend
Guide for adding a backend (Rust or Python) to the agent-sec-core security middleware. Use when creating new backends, integrating Rust or Python code into the security middleware, or extending with new backend actions.
coding
Agent Device
Drive iOS and Android devices for the Expensify App - testing, debugging, performance profiling, bug reproduction, and feature verification. Use when the developer needs to interact with the mobile app on a device.