From claude-initial-setup
Guide Python type annotations using the typing module: Protocol, TypeVar, ParamSpec, Generic, Literal, TypeAlias, overload, and dataclass field typing. Use when the user writes Python type hints, asks about typing, creates generic classes, defines protocols, or works with mypy/pyright. Trigger when you see untyped Python code that should be typed.
npx claudepluginhub versoxbt/claude-initial-setup --plugin claude-initial-setupThis skill uses the workspace's default tool permissions.
Write precise, expressive type annotations that catch bugs at static analysis time.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Write precise, expressive type annotations that catch bugs at static analysis time. Modern Python typing (3.10+) is powerful enough to express complex relationships without runtime overhead.
Prefer built-in generics and union syntax over typing imports.
# Python 3.10+ -- use built-in types and | union
def process_items(
items: list[str],
config: dict[str, int | float],
callback: Callable[[str], None] | None = None,
) -> tuple[int, list[str]]:
...
# For older Python, import from typing
from typing import List, Dict, Optional, Union, Tuple
Use TypeVar for functions/classes that work with any type while preserving type relationships.
from typing import TypeVar, Generic
T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")
class Result(Generic[T]):
"""A container that holds either a value or an error."""
def __init__(self, value: T | None = None, error: str | None = None):
self._value = value
self._error = error
def unwrap(self) -> T:
if self._error is not None:
raise ValueError(self._error)
assert self._value is not None
return self._value
def map(self, func: Callable[[T], V]) -> "Result[V]":
if self._error:
return Result(error=self._error)
return Result(value=func(self.unwrap()))
# Bounded TypeVar -- restrict to specific types
Numeric = TypeVar("Numeric", int, float)
def add(a: Numeric, b: Numeric) -> Numeric:
return a + b
# Upper bound -- must be subclass of
from datetime import datetime
DateLike = TypeVar("DateLike", bound=datetime)
Use Protocol instead of ABCs when you want duck typing with static checking. This is Python's answer to Go-style interfaces.
from typing import Protocol, runtime_checkable
@runtime_checkable
class Renderable(Protocol):
def render(self) -> str: ...
class SupportsComparison(Protocol):
def __lt__(self, other: "SupportsComparison") -> bool: ...
def __eq__(self, other: object) -> bool: ...
# Any class with a render() -> str method satisfies Renderable
# No inheritance needed
class HtmlWidget:
def render(self) -> str:
return "<div>widget</div>"
def display(item: Renderable) -> None:
print(item.render())
display(HtmlWidget()) # Works -- structural match
Use ParamSpec for decorators that preserve the wrapped function's signature.
from typing import ParamSpec, TypeVar, Callable
import functools
P = ParamSpec("P")
R = TypeVar("R")
def log_calls(func: Callable[P, R]) -> Callable[P, R]:
"""Decorator that logs function calls while preserving type info."""
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_calls
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
# Type checker knows: greet(name: str, greeting: str = "Hello") -> str
from typing import Literal, TypeAlias, overload
# Literal -- restrict to exact values
Direction: TypeAlias = Literal["north", "south", "east", "west"]
LogLevel: TypeAlias = Literal["debug", "info", "warning", "error"]
def set_log_level(level: LogLevel) -> None:
...
# TypeAlias -- name complex types
JsonPrimitive: TypeAlias = str | int | float | bool | None
JsonValue: TypeAlias = JsonPrimitive | list["JsonValue"] | dict[str, "JsonValue"]
UserHandler: TypeAlias = Callable[[str, dict[str, str]], "Response"]
# Overload -- different return types based on input
@overload
def parse(raw: str, as_list: Literal[True]) -> list[str]: ...
@overload
def parse(raw: str, as_list: Literal[False] = ...) -> str: ...
def parse(raw: str, as_list: bool = False) -> str | list[str]:
if as_list:
return raw.split(",")
return raw.strip()
from dataclasses import dataclass, field
from typing import ClassVar
@dataclass
class Config:
# Required fields
host: str
port: int
# Optional with defaults
debug: bool = False
tags: list[str] = field(default_factory=list)
# ClassVar -- not included in __init__ or __repr__
MAX_RETRIES: ClassVar[int] = 3
# InitVar -- passed to __init__ but not stored as field
from dataclasses import InitVar
password: InitVar[str] = ""
def __post_init__(self, password: str) -> None:
self._hashed = hash(password) if password else 0
from typing import TypeGuard, TypeIs
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
"""Narrow list[object] to list[str]."""
return all(isinstance(item, str) for item in val)
# Python 3.13+ TypeIs -- narrower and more precise than TypeGuard
def is_int(val: int | str) -> TypeIs[int]:
return isinstance(val, int)
def process(val: int | str) -> None:
if is_int(val):
# val is narrowed to int
print(val + 1)
else:
# val is narrowed to str (TypeIs does this, TypeGuard does not)
print(val.upper())
Any to silence type errors: Fix the actual type issue. Any disables
all checking and defeats the purpose.Optional[X] confusion: Optional[X] means X | None, not "this parameter
is optional." Use X | None for clarity (Python 3.10+).@runtime_checkable on Protocols: Without it, isinstance() checks
against the Protocol will fail at runtime.object instead.# type: ignore comments: Each suppression should have a specific
error code: # type: ignore[assignment]. Never use bare # type: ignore.| Construct | Purpose |
|---|---|
T = TypeVar("T") | Generic type parameter |
TypeVar("T", bound=Base) | Upper-bounded generic |
Protocol | Structural subtyping (duck typing) |
ParamSpec("P") | Preserve callable signatures |
Literal["a", "b"] | Exact value types |
TypeAlias | Name complex type expressions |
@overload | Multiple return types by input |
TypeGuard[X] | Custom type narrowing |
ClassVar[int] | Class-level (not instance) field |
Final[str] | Immutable binding |