← pstackCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to pstack
Snapshot Sep 30, 2026 · 23:14 UTC · version 0.2.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "TypeScript best practices. Use when reading or editing any .ts or .tsx file.",
"included_files": [
{
"relative_path": "references/patterns.md",
"size_in_bytes": 8695
}
],
"name": "typescript-best-practices",
"skill_md_contents": "---\nname: typescript-best-practices\ndescription: TypeScript best practices. Use when reading or editing any .ts or .tsx file.\n---\n\n# TypeScript best practices\n\nApply the **type-system-discipline** principle skill first; this skill grounds it in TypeScript syntax.\n\n| Rule | Summary |\n|------|---------|\n| Discriminated unions | Model variants with a `kind` literal discriminant so impossible states can't be represented. No optional-field bags. |\n| Branded types | Brand primitives with `& { readonly __brand: \"X\" }` so they can't be mixed up. Validate once at creation. |\n| Constructive modeling | Build the shape so the illegal value can't be constructed. `[T, ...T[]]` for non-empty, `[T, T][]` for even length, `start` plus `duration` for a range. Not a runtime guard, not a wish for refinement types. |\n| Simplest total type | Keep `T[]` while every operation on it stays total. Strengthen to `NonEmpty<T>` only where the loose type forces `!`, a cast, or a \"should never happen\" throw. |\n| `unknown` over `any` | External data is `unknown`. `any` disables type checking everywhere it touches. |\n| No `as` casts | Every `as` is a runtime crash waiting. Cast only after validation. |\n| Narrowing hierarchy | Discriminant switch > `in` operator > `typeof`/`instanceof` > user-defined type guard > `as`. |\n| Type guards | Must verify the claim. A lying guard is worse than `as` because the bug hides behind a name that says it's safe. Name them `isX` or `hasX`. |\n| Exhaustiveness | Inline `const _exhaustive: never = x;` in default arms so the compiler errors when a new variant is added. |\n| `satisfies` over `as` | Validates the value without widening literal types. |\n| Boundary validation | Validate where data crosses in; trust types inside. See the **boundary-discipline** principle skill. |\n| Schema-derived types | Reach for `Pick`/`Omit`/`Parameters`/`ReturnType`/`Awaited`/`typeof` before declaring a new interface. |\n| Object args | Pass objects, not positional, so argument order is self-documenting. Skip on hot paths (per-frame render, tokenizers, parsers). |\n| Real tests | Don't mock what you can run. Prefer the framework's real test primitives with leak/disposable checks, and verify UI in a running build. Mock only what you can't run locally. |\n| Structured telemetry | Prefer structured logger diagnostics with enough context to debug from an id. No `console.log` in shipped code. |\n\nExamples: `references/patterns.md`.\n"
}SHA-256 of public snapshot: 0b62d4144656c39d0965ff440bb9de4e6c42deeccb9e7d73b1aea0574064a9e9