← fstackCONTENT HISTORY

Update to fstack

Snapshot Sep 30, 2026 · 23:16 UTC · version 1.1.2

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full 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": 8987
    }
  ],
  "name": "typescript-best-practices",
  "skill_md_contents": "---\r\nname: typescript-best-practices\r\ndescription: TypeScript best practices. Use when reading or editing any .ts or .tsx file.\r\nmenu-description: ground type-system discipline in TypeScript syntax\r\n---\r\n\r\n# TypeScript best practices\r\n\r\nApply the **type-system-discipline** principle skill first; this skill grounds it in TypeScript syntax.\r\n\r\n| Rule | Summary |\r\n|------|---------|\r\n| Discriminated unions | Model variants with a `kind` literal discriminant so impossible states can't be represented. No optional-field bags. |\r\n| Branded types | Brand primitives with `& { readonly __brand: \"X\" }` so they can't be mixed up. Validate once at creation. |\r\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. |\r\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. |\r\n| `unknown` over `any` | External data is `unknown`. `any` disables type checking everywhere it touches. |\r\n| No `as` casts | Every `as` is a runtime crash waiting. Cast only after validation. |\r\n| Narrowing hierarchy | Discriminant switch > `in` operator > `typeof`/`instanceof` > user-defined type guard > `as`. |\r\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`. |\r\n| Exhaustiveness | Inline `const _exhaustive: never = x;` in default arms so the compiler errors when a new variant is added. |\r\n| `satisfies` over `as` | Validates the value without widening literal types. |\r\n| Boundary validation | Parse where data crosses in, into a named domain type. `Record<string, unknown>` (however spelled) stops at that parse. Trust types inside. See the **boundary-discipline** principle skill. |\r\n| Schema-derived types | Reach for `Pick`/`Omit`/`Parameters`/`ReturnType`/`Awaited`/`typeof` before declaring a new interface. |\r\n| Object args | Pass objects, not positional, so argument order is self-documenting. Skip on hot paths (per-frame render, tokenizers, parsers). |\r\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. |\r\n| Structured telemetry | Prefer structured logger diagnostics with enough context to debug from an id. No `console.log` in shipped code. |\r\n\r\nExamples: `references/patterns.md`.\r\n"
}

SHA-256 of public snapshot: bc61bb9749718f39325385eea0938d2717c9a8b0cf9a41ef13efb44f9d7be6de