docs: add Python type hints best practices guide#4
docs: add Python type hints best practices guide#4agent-kurouto[bot] wants to merge 3 commits intodevfrom
Conversation
Add docs/type-hints.md with a comprehensive deep-dive on type hints: modern syntax, typing module essentials, Protocols, Generics, Pyright configuration, special cases (dataclasses, overloads, generators), and common anti-patterns. Cross-reference the guide from Section 2 of python/best-practices.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a dedicated documentation guide for Python type-hinting best practices and links to it from the existing Python best-practices doc, aligning with the existing “Logging Guide” cross-reference pattern.
Changes:
- Add
docs/type-hints.mdwith a 10-section deep-dive on Python typing best practices. - Add a cross-reference link in
python/best-practices.mdpointing readers to the new guide.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
python/best-practices.md |
Adds a “Type Hints Guide” cross-reference link in the type-hints section. |
docs/type-hints.md |
New comprehensive type-hints best-practices guide (syntax, typing constructs, protocols/generics, pyright, and anti-patterns). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
docs/type-hints.md
Outdated
| from typing import TypeVar | ||
| from numbers import Number | ||
|
|
||
| Numeric = TypeVar("Numeric", int, float, complex) # union constraint | ||
| Comparable = TypeVar("Comparable", bound="SupportsLessThan") # upper bound | ||
|
|
||
| def maximum(a: Numeric, b: Numeric) -> Numeric: | ||
| return a if a > b else b |
docs/type-hints.md
Outdated
| from typing import TypeVarTuple, Unpack | ||
|
|
||
| Ts = TypeVarTuple("Ts") | ||
|
|
||
| def broadcast(func: Callable[[Unpack[Ts]], None], *args: Unpack[Ts]) -> None: | ||
| func(*args) |
| # Avoid — loses all type safety | ||
| def process(data: Any) -> Any: | ||
| return data["value"] | ||
|
|
||
| # Prefer — even a broad type is better than Any | ||
| def process(data: dict[str, object]) -> object: | ||
| return data["value"] | ||
|
|
||
| # Use Any sparingly, document why | ||
| def parse_legacy_response(raw: bytes) -> Any: | ||
| # Legacy API returns inconsistent shapes; typed in follow-up issue #42 | ||
| return json.loads(raw) | ||
| ``` |
|
|
||
| # Avoid (legacy) | ||
| from typing import Optional, Union | ||
| def process(value: Union[int, str, None]) -> List[str]: ... |
docs/type-hints.md
Outdated
| For Python 3.7–3.9, add this import at the top of any module to enable the 3.10+ union syntax and forward references without quotes. It makes all annotations strings (lazy evaluation), so they don't affect runtime performance. | ||
|
|
||
| ```python | ||
| from __future__ import annotations | ||
|
|
||
| def build(parts: list[str], separator: str | None = None) -> str: | ||
| return (separator or "").join(parts) |
docs/type-hints.md
Outdated
| from typing import TypeAlias | ||
|
|
||
| # Give a meaningful name to a complex type | ||
| Headers: TypeAlias = dict[str, str] | ||
| Callback: TypeAlias = Callable[[int, str], bool] | ||
| Matrix: TypeAlias = list[list[float]] |
docs/type-hints.md
Outdated
| from typing import Callable | ||
|
|
||
| # Callable[[arg_types...], return_type] | ||
| Handler: TypeAlias = Callable[[str, int], bool] | ||
|
|
||
| def register(event: str, handler: Callable[[str], None]) -> None: ... | ||
|
|
||
| # No-argument callable returning nothing | ||
| Thunk: TypeAlias = Callable[[], None] | ||
| ``` |
Address 7 review comments from Copilot: - `TypeAlias` snippet: add missing `Callable` import - `Callable` snippet: add missing `TypeAlias` import - Legacy union snippet: add missing `List` import - Bounded TypeVar: define `SupportsLessThan` Protocol, drop unorderable `complex` from the union constraint, use `<` instead of `>` for the comparable example - `Unpack`/`TypeVarTuple` snippet: add missing `Callable` import - `Any` anti-pattern snippet: add missing `import json` and `from typing import Any` - `from __future__ import annotations` section: rewrite to clarify it postpones evaluation / enables forward refs without quotes, but does NOT enable `X | Y` syntax on Python 3.7–3.9 (that requires 3.10+) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Self-Review NotesOverall this is a solid, well-structured guide. Here are a few observations from a fresh pass: ✅ Strengths
🔍 Minor Observations
💡 Ideas for Future TopicsBased on what this repo already covers (type hints, logging), here are natural next guides to add:
The Testing and Error Handling topics would probably have the highest immediate value for teams adopting this guide. 🤖 Generated with Claude Code |
…rt_never, Annotated, cross-refs - Add `NewType` subsection to Section 4: zero-runtime-cost semantic type distinctions with worked example showing UserId vs OrderId mixing error - Add `TypeGuard` subsection: custom narrowing predicates with a list[object] → list[str] guard example - Add `assert_never` subsection: exhaustive Literal/Union matching with a Status literal example; explains how Pyright surfaces unhandled variants - Add `Annotated` subsection: embedding Pydantic v2 Field constraints and FastAPI Path/Query constraints directly in type annotations - Add cross-reference from the `from __future__ import annotations` section (Section 3) pointing readers to the TYPE_CHECKING section (Section 7) - Expand Table of Contents entry for Section 4 with all new subsection names - Add PEP 593 (Annotated), PEP 612 (ParamSpec), PEP 646 (TypeVarTuple), and PEP 673 (Self) to Further Reading Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
docs/type-hints.md: a comprehensive deep-dive guide on Python type hints best practices, following the same format asdocs/logging.mdtypingmodule essentials (TypeAlias,Callable,Literal,TypedDict,overload), Protocols & structural subtyping, Generics &TypeVar, runtime vs. static typing, Pyright configuration, special cases (dataclasses,NamedTuple,Self, generators, async), and common anti-patternspython/best-practices.mdSection 2 with a cross-reference link to the new guide, mirroring the pattern used fordocs/logging.mdTest plan
docs/type-hints.mdfor accuracy and completenesspython/best-practices.mdSection 2 resolves correctlydocs/logging.mdCloses PLT-1024
🤖 Generated with Claude Code