bateau84/skills

python-type-checking

Static typing for Python — type hints, generics, Optional/None handling, Union and the X | Y syntax, Literal, Protocol (structural typing), TypedDict, typing.cast, gradual typing, and running a static checker (mypy, ty, or pyright) in CI.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/bateau84/skills --skill python-type-checking

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Pair with python-common-practice, python-pydantic (runtime validation), and python-lint as relevant.

Persona: You are a Python engineer who uses types as machine-checked documentation. A correct annotation prevents a class of bugs without a single test.

Static Typing

Type hints are checked by a separate tool, not the interpreter — Python ignores them at runtime. Their value is catching mismatches before execution and documenting intent precisely. Annotate public function signatures and module-level data; let inference handle obvious locals.

Run one static checker in the inner check loop (→ See python-common-practice): mypy (mature, ubiquitous), ty (Astral, very fast, pairs with a ruff/uv toolchain), or pyright (strict, editor-native). Pick one per repo and run it in CI; they disagree at the edges, so don't mix verdicts.

Annotate signatures, infer locals

python
def fuzzy_match(a: str, b: str, threshold: int = 80) -> bool:
    score = ratio(a, b)        # inferred int — no annotation needed
    return score >= threshold

Use modern syntax (target a recent requires-python):

  • list[str], dict[str, int], tuple[int, ...] — builtins, not typing.List.
  • X | Y and X | None — not Union[X, Y] / Optional[X].
  • from collections.abc import Iterable, Callable, Sequence — not the deprecated typing aliases.

None is the most common bug — model it

X | None forces callers to handle absence. The checker then proves you narrowed it before use — this is where typing pays for itself.

python
def find_user(uid: int) -> User | None: ...

u = find_user(1)
print(u.name)        # ✗ checker error: u may be None
if u is not None:
    print(u.name)    # ✓ narrowed to User inside the guard

Prefer narrowing (if x is None: return) over cast or assert. A cast silences the checker without proving anything; reserve it for cases the checker genuinely can't follow, and comment why.

Protocols — structural typing over inheritance

A Protocol matches any object with the right shape, so you depend on a capability, not a base class. This is the typed version of duck typing and keeps modules decoupled (no shared base import).

python
from typing import Protocol

class MatchRepository(Protocol):
    def save(self, decision: MatchDecision) -> None: ...
    def by_video(self, video_id: str) -> MatchDecision | None: ...

def record(repo: MatchRepository, d: MatchDecision) -> None:
    repo.save(d)        # any class with these methods satisfies the type

Use Protocol for ports/interfaces (the SQLite repo, an API client) so tests can pass a lightweight fake that simply has the methods.

Other high-value tools

  • Literal["allow", "deny"] — a closed set of string values, checked at call sites.
  • TypedDict — a dict with known string keys and per-key types (for JSON payloads you don't model with Pydantic).
  • @overload — different return types for different argument shapes.
  • typing.Final — a constant that must not be reassigned.

Gradual typing

You don't have to type everything at once. Start strict on new modules; let legacy modules stay loose. In mypy, ratchet up with disallow_untyped_defs per-package rather than globally on day one — an all-or-nothing flip drowns you in errors and teaches nothing.

toml
[tool.mypy]
python_version = "3.13"
warn_unused_ignores = true
warn_redundant_casts = true
# strict = true   # turn on per-package as coverage grows

Common mistakes

MistakeFix
Optional[X] / Union[A, B] / List[str]Use `XNone, AB, list[str]`.
cast to silence a None errorNarrow with an is None guard; reserve cast for genuinely opaque cases, with a comment.
Any to make an error disappearAny disables checking for that value; use a precise type or object + narrowing.
Inheriting a base class just for typingDefine a Protocol; depend on shape, not lineage.
Bare # type: ignorePin the error code: # type: ignore[arg-type]; warn_unused_ignores cleans stale ones.
Type checker not in CIAdd it to the inner loop and CI, or annotations silently rot.

Diagnose: 1- mypy . / ty check / pyright — the type checker is itself the diagnostic; read its output before "fixing" by adding Any 2- reveal_type(x) in a checked file — prints the inferred type so you see what the checker sees.

References

Related by task

from this repository

More skills

All skills
bateau84
Community

behavioral-spec

Derive bounded, implementation-independent requirements from agreed product intent through goal refinement, coverage lenses, obstacle analysis, provenance tracking, and counterexample checks. Use to select, author, and reconcile Behavioral Requirements (BR), Quality Scenarios (QS), and Obligation Contracts (OC) without expanding scope. Not for concrete API/schema/protocol realization (use architectural-spec) or human-centered stories and scenarios (use user-stories-and-scenarios).

installs
1
GitHub stars
0
Updated
Oct 18
bateau84
Community

desktop-ui-design

Desktop GUI design for native and hybrid applications: platform conventions (macOS HIG, Windows Fluent, GNOME HIG), menus, keyboard shortcuts, window management, session persistence, native vs Electron/Tauri trade-offs, and accessibility APIs. Use for Swift/AppKit, C/WinUI, GTK+, or Electron/Tauri/Flutter desktop design. Add web-ui-design for a web app shipped as a desktop wrapper. Not for browser-only interfaces, terminal applications (use tui-design), or command-line tools (use cli-design).

installs
1
GitHub stars
0
Updated
Oct 18
bateau84
Community

git-commit-discipline

Small coherent commits, explanatory messages, shared-working-tree discipline, and safe undo/recovery. Use when asked to commit, when a diff mixes concerns, when agents share a working tree, or when undoing or recovering Git changes. Not for content conflicts (use git-conflicts).

installs
1
GitHub stars
0
Updated
Oct 18
bateau84
Community

golang-dependency-injection

google/wire, uber-go/dig, uber-go/fx, samber/do, manual constructor injection, and service containers in Go. Use when designing service architecture, setting up dependency injection, refactoring tightly coupled code, or managing singletons and service factories.

installs
1
GitHub stars
0
Updated
Oct 18