better typing

This commit is contained in:
John Lancaster
2026-06-21 15:41:22 -05:00
parent 57347077a9
commit 4f05f13e45
3 changed files with 62 additions and 0 deletions
@@ -29,6 +29,46 @@ This workflow is distilled from practical typing modernization passes and is des
- If a stricter type (for example `Literal`) may reject existing runtime inputs:
- apply only when the input contract is already finite; otherwise defer with a contract-change note.
## Deterministic Narrowing with `match`
Use structural pattern matching when the domain is a closed set (for example tagged unions, enum dispatch, or finite literal variants).
1. Prefer `match` over long `if`/`elif` ladders when each branch represents a distinct variant.
2. For tagged unions, match the discriminant and extract payload fields in the same case.
3. Add a default `case _:` branch with `assert_never(...)` to enforce exhaustiveness in static analysis.
4. Keep patterns explicit and side-effect-light; avoid relying on bindings from failed matches.
Example with a tagged `TypedDict` union:
```python
from typing import Literal, TypedDict, assert_never
class NewJobEvent(TypedDict):
tag: Literal["new-job"]
job_name: str
class CancelJobEvent(TypedDict):
tag: Literal["cancel-job"]
job_id: int
type Event = NewJobEvent | CancelJobEvent
def route(event: Event) -> str:
match event:
case {"tag": "new-job", "job_name": job_name}:
return f"enqueue:{job_name}"
case {"tag": "cancel-job", "job_id": job_id}:
return f"cancel:{job_id}"
case _:
assert_never(event)
```
This pattern makes narrowing deterministic per branch and surfaces missing variants as type-checker errors during review.
## Quality Criteria
1. All edits are syntax-valid for the target Python versions.