Python type safety with type hints, generics, protocols

by wshobson · MIT license · ★ 39,857 on GitHub · updated Sep 21

Python type safety cover

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.

---
name: python-type-safety
description: 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.
---

# 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

Overview

Leverage Python's type system to catch errors at static analysis time. Type annotations serve as enforced documentation that tooling validates automatically.

Manual install (npx, ZIP)
Claude Codenpx skills add wshobson/agents --skill python-type-safety -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/wshobson/agents/tar.gz/4236bb91f839 \ | tar -xz -C ~/.claude/skills --strip-components=4 agents-4236bb91f839/plugins/python-development/skills/python-type-safety
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/5d496fceb8b7575672e9/python-type-safety.zip" -OutFile "$env:TEMP\python-type-safety.zip"; Expand-Archive "$env:TEMP\python-type-safety.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md5.6 KB
  • references/1 file · 5.7 KB
Read the files here
wshobson/4236bb92 files
SKILL.md
Show the full text201 lines

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

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.

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.

# 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.

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.

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
1---
2name: python-type-safety
3description: 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.
4---
5 
6# Python Type Safety
7 
8Leverage Python's type system to catch errors at static analysis time. Type annotations serve as enforced documentation that tooling validates automatically.
9 
10## When to Use This Skill
11 
12- Adding type hints to existing code
13- Creating generic, reusable classes
14- Defining structural interfaces with protocols
15- Configuring mypy or pyright for strict checking
16- Understanding type narrowing and guards
17- Building type-safe APIs and libraries
18 
19## Core Concepts
20 
21### 1. Type Annotations
22 
23Declare expected types for function parameters, return values, and variables.
24 
25### 2. Generics
26 
27Write reusable code that preserves type information across different types.
28 
29### 3. Protocols
30 
31Define structural interfaces without inheritance (duck typing with type safety).
32 
33### 4. Type Narrowing
34 
35Use guards and conditionals to narrow types within code blocks.
36 
37## Quick Start
38 
39```python
40def get_user(user_id: str) -> User | None:
41 """Return type makes 'might not exist' explicit."""
42 ...
43 
44# Type checker enforces handling None case
45user = get_user("123")
46if user is None:
47 raise UserNotFoundError("123")
48print(user.name) # Type checker knows user is User here
49```
50 
51## Fundamental Patterns
52 
53### Pattern 1: Annotate All Public Signatures
54 
55Every public function, method, and class should have type annotations.
56 
57```python
58def get_user(user_id: str) -> User:
59 """Retrieve user by ID."""
60 ...
61 
62def process_batch(
63 items: list[Item],
64 max_workers: int = 4,
65) -> BatchResult[ProcessedItem]:
66 """Process items concurrently."""
67 ...
68 
69class UserRepository:
70 def __init__(self, db: Database) -> None:
71 self._db = db
72 
73 async def find_by_id(self, user_id: str) -> User | None:
74 """Return User if found, None otherwise."""
75 ...
76 
77 async def find_by_email(self, email: str) -> User | None:
78 ...
79 
80 async def save(self, user: User) -> User:
81 """Save and return user with generated ID."""
82 ...
83```
84 
85Use `mypy --strict` or `pyright` in CI to catch type errors early. For existing projects, enable strict mode incrementally using per-module overrides.
86 
87### Pattern 2: Use Modern Union Syntax
88 
89Python 3.10+ provides cleaner union syntax.
90 
91```python
92# Preferred (3.10+)
93def find_user(user_id: str) -> User | None:
94 ...
95 
96def parse_value(v: str) -> int | float | str:
97 ...
98 
99# Older style (still valid, needed for 3.9)
100from typing import Optional, Union
101 
102def find_user(user_id: str) -> Optional[User]:
103 ...
104```
105 
106### Pattern 3: Type Narrowing with Guards
107 
108Use conditionals to narrow types for the type checker.
109 
110```python
111def process_user(user_id: str) -> UserData:
112 user = find_user(user_id)
113 
114 if user is None:
115 raise UserNotFoundError(f"User {user_id} not found")
116 
117 # Type checker knows user is User here, not User | None
118 return UserData(
119 name=user.name,
120 email=user.email,
121 )
122 
123def process_items(items: list[Item | None]) -> list[ProcessedItem]:
124 # Filter and narrow types
125 valid_items = [item for item in items if item is not None]
126 # valid_items is now list[Item]
127 return [process(item) for item in valid_items]
128```
129 
130### Pattern 4: Generic Classes
131 
132Create type-safe reusable containers.
133 
134```python
135from typing import TypeVar, Generic
136 
137T = TypeVar("T")
138E = TypeVar("E", bound=Exception)
139 
140class Result(Generic[T, E]):
141 """Represents either a success value or an error."""
142 
143 def __init__(
144 self,
145 value: T | None = None,
146 error: E | None = None,
147 ) -> None:
148 if (value is None) == (error is None):
149 raise ValueError("Exactly one of value or error must be set")
150 self._value = value
151 self._error = error
152 
153 @property
154 def is_success(self) -> bool:
155 return self._error is None
156 
157 @property
158 def is_failure(self) -> bool:
159 return self._error is not None
160 
161 def unwrap(self) -> T:
162 """Get value or raise the error."""
163 if self._error is not None:
164 raise self._error
165 return self._value # type: ignore[return-value]
166 
167 def unwrap_or(self, default: T) -> T:
168 """Get value or return default."""
169 if self._error is not None:
170 return default
171 return self._value # type: ignore[return-value]
172 
173# Usage preserves types
174def parse_config(path: str) -> Result[Config, ConfigError]:
175 try:
176 return Result(value=Config.from_file(path))
177 except ConfigError as e:
178 return Result(error=e)
179 
180result = parse_config("config.yaml")
181if result.is_success:
182 config = result.unwrap() # Type: Config
183```
184 
185## Detailed worked examples and patterns
186 
187Detailed sections (starting with `## Advanced Patterns`) live in `references/details.md`. Read that file when the navigation summary above is insufficient.
188 
189## Best Practices Summary
190 
1911. **Annotate all public APIs** - Functions, methods, class attributes
1922. **Use `T | None`** - Modern union syntax over `Optional[T]`
1933. **Run strict type checking** - `mypy --strict` in CI
1944. **Use generics** - Preserve type info in reusable code
1955. **Define protocols** - Structural typing for interfaces
1966. **Narrow types** - Use guards to help the type checker
1977. **Bound type vars** - Restrict generics to meaningful types
1988. **Create type aliases** - Meaningful names for complex types
1999. **Minimize `Any`** - Use specific types or generics. `Any` is acceptable for truly dynamic data or when interfacing with untyped third-party code
20010. **Document with types** - Types are enforceable documentation
201 
View all files on GitHub →

Details

Updated
Sep 21, 2026
License
MIT
Stars on the repo
★ 39,857
Checked
Source
wshobson/agents ↗
Creator
wshobson · 179 listings
View creator

Similar skills

See all →
SkillExtract text, tables, metadataXberg Document Extractionxberg-io/xberg · by xberg-ioExtract text, tables, metadata, and images from 107 document formats (PDF, Office, images, HTML, email, archives, academic) using Xberg. Use when writing code that calls Xberg APIs in Python, Node.js/TypeScript, Rust, or CLI. Covers installation, extraction (sync/async), configuration (OCR, chunking, output format), batch processing, error handling, and plugins.★ 9.4k GitHub starsSkillMove code from one implementation to another functionCode migrationkucherenko/jscpd · by kucherenkoMove code from one implementation to another function by function, tests first and code second, and check two implementations of one app for parity, with jscpd --compare as the progress measure and a coverage map binding each function to its tests. Use when porting a library or app to another language or framework (Java to Kotlin, JavaScript to Rust, a Python library to TypeScript, an iOS app to Android), when asked what is left to port, or when comparing the Android and iOS versions of an app.★ 6.3k GitHub starsSkillManages Ahrefs API usage in Python using ahrefs-pythonOpenClaudia/openclaudia-skills · by OpenClaudiaManages Ahrefs API usage in Python using `ahrefs-python` library. Use when working with SEO / marketing related tasks or with data including backlinks, keywords, domain ratings, organic traffic, site audits, rank tracking, and brand monitoring. Covers `ahrefs-python` usage including AhrefsClient / AsyncAhrefsClient, typed request/response models, error handling, and all API sections.★ 705 GitHub starsMCPDocx LLM translatoradeudealfluence/adeu · by dealfluenceDocx ↔ LLM translator. Projects .docx office files to Markdown for editing. Projects edits back to OOXML as tracked changes (redlines). Python and Node.js implementations.★ 165 GitHub starsSkillCreate an Amazon-compliant white-background main imageAmazon White-Background Main Image · 亚马逊白底主图xianyu110/ecommerce-image-skills · by xianyu110Create an Amazon-compliant white-background main image (pure #FFFFFF background, product fills ≥85% of the frame, no text, props or watermark) from a product photo with GPT Image 2.5, then verify it with a Python check script. Use for Amazon/Walmart/eBay main images, 白底图, 白底主图, hero image, listing main photo.★ 92 GitHub starsMCPOfficial monorepo of SDKs, CLISendmux sdkSendmux/sendmux-sdk · by SendmuxOfficial monorepo of SDKs, CLI, and MCP servers for Sendmux email APIs across TypeScript, Python, Go, PHP, Rust, and Ruby.★ 65 GitHub stars

More from wshobson

SkillMaster C/.NET backend development patterns for buildingwshobson/agents · by wshobsonMaster C#/.NET backend development patterns for building robust APIs, MCP servers, and enterprise applications. Covers async/await, dependency injection, Entity Framework Core, Dapper, configuration, caching, and testing with xUnit. Use when developing .NET backends, reviewing C# code, or designing API architectures.★ 39.9k GitHub starsSkillImplement WCAG 2.2 compliant interfaces with mobileAccessibility compliancewshobson/agents · by wshobsonImplement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.★ 39.9k GitHub starsSkillMaster Material Design 3 and Jetpack Compose patternsAndroid Mobile Designwshobson/agents · by wshobsonMaster Material Design 3 and Jetpack Compose patterns for building native Android apps. Use when designing Android interfaces, implementing Compose UI, or following Google's Material Design guidelines.★ 39.9k GitHub starsSkillMigrate from AngularJS to Angular using hybrid modeAngular migrationwshobson/agents · by wshobsonMigrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.★ 39.9k GitHub starsSkillUnderstand anti-reversing, obfuscationAnti reversing techniqueswshobson/agents · by wshobsonUnderstand anti-reversing, obfuscation, and protection techniques encountered during software analysis. Use this skill when analyzing malware evasion techniques, when implementing anti-debugging protections for CTF challenges, when reverse engineering packed binaries, or when building security research tools that need to detect virtualized environments.★ 39.9k GitHub starsSkillBuild production Apache Airflow DAGs with best practicesApache Airflow DAG Patternswshobson/agents · by wshobsonBuild production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. Use when creating data pipelines, orchestrating workflows, or scheduling batch jobs.★ 39.9k GitHub stars