[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7ESWJRXQQD64VXT86CSVDPY":3,"skill-same:01M7ESWJRXQQD64VXT86CSVDPY":59},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":16,"sourceHtmlUrl":17,"categories":18,"keywords":19,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":23,"frontMatter":24,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":14,"repositoryHtmlUrl":28,"repositoryHomepageUrl":6,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":30,"install":31,"resources":44},"01M7ESWJRXQQD64VXT86CSVDPY","typescript-best-practices",null,"TypeScript best practices. Use when reading or editing any .ts or .tsx file.","vultuk\u002Fskills-plugins","vultuk","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F271838?v=4","01M7ES3YGAEPNBHP83DJ2947AC","Simon Skinner","01M7ES3YGX2PJTT1E2DXQWZ30H",0,"MIT","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: typescript-best-practices\ndescription: \"TypeScript best practices. Use when reading or editing any .ts or .tsx file.\"\n---\n\n\n# TypeScript best practices\n\nApply the **type-system-discipline** principle skill first.\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 the boundary. |\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\u003CT>` only where the loose type forces `!`, a cast, or a \"should never happen\" throw. |\n| `unknown` over `any` | External data is `unknown`. |\n| Schemas before guards | Before hand-writing a property-by-property type guard, use the repository's runtime schema library and infer the type from the schema, such as `z.infer`. |\n| No `as` casts | Every `as` is a runtime crash waiting. Cast only after validation. |\n| Narrowing hierarchy | Discriminant switch > `in` operator > `typeof`\u002F`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 | Parse where data crosses in, into a named domain type. `Record\u003Cstring, unknown>` (however spelled) stops at that parse. Trust types inside. See the **boundary-discipline** principle skill. |\n| Schema-derived types | Reach for `Pick`\u002F`Omit`\u002F`Parameters`\u002F`ReturnType`\u002F`Awaited`\u002F`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\u002Fdisposable 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\u002Fpatterns.md`.\n","# TypeScript best practices\n\nApply the **type-system-discipline** principle skill first.\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 the boundary. |\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\u003CT>` only where the loose type forces `!`, a cast, or a \"should never happen\" throw. |\n| `unknown` over `any` | External data is `unknown`. |\n| Schemas before guards | Before hand-writing a property-by-property type guard, use the repository's runtime schema library and infer the type from the schema, such as `z.infer`. |\n| No `as` casts | Every `as` is a runtime crash waiting. Cast only after validation. |\n| Narrowing hierarchy | Discriminant switch > `in` operator > `typeof`\u002F`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 | Parse where data crosses in, into a named domain type. `Record\u003Cstring, unknown>` (however spelled) stops at that parse. Trust types inside. See the **boundary-discipline** principle skill. |\n| Schema-derived types | Reach for `Pick`\u002F`Omit`\u002F`Parameters`\u002F`ReturnType`\u002F`Awaited`\u002F`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\u002Fdisposable 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\u002Fpatterns.md`.\n",{"name":5,"description":7},"main","70adcb793e5f48e0e95760801c06c2b4a1b884c4","plugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins","https:\u002F\u002Fgithub.com\u002Fvultuk","2026-10-15 16:01:08",{"source":8,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add vultuk\u002Fskills-plugins --skill typescript-best-practices",{"tool":37,"command":38},"bunx","bunx skills add vultuk\u002Fskills-plugins --skill typescript-best-practices",{"tool":40,"command":41},"pnpm","pnpm dlx skills add vultuk\u002Fskills-plugins --skill typescript-best-practices","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002FSKILL.md",true,[45,51,55],{"path":46,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":49,"sourceHtmlUrl":50},"agents\u002Fopenai.yaml","REFERENCE","参考文档",43,"https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002Fagents\u002Fopenai.yaml",{"path":52,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":54,"sourceHtmlUrl":16},"LICENSE","许可证",1067,{"path":56,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":57,"sourceHtmlUrl":58},"references\u002Fpatterns.md",9214,"https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002Freferences\u002Fpatterns.md",[60,68,76,84,92,100],{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":64,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":20},"01M7ESXCFVAZ812CJE3B55Q2P9","why","Use for 'why does X work this way', 'why we picked Y', design rationale, regressions, postmortems, or data-backed thresholds. Discovers available MCPs and queries each evidence category (source control, issue tracker, long-form docs, real-time chat, infrastructure observability, error tracking, product analytics warehouse) in parallel, then returns a cited read on decisions and tradeoffs. Use how for runtime behavior.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fwhy\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fwhy\u002FSKILL.md",[],[],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":72,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":20},"01M7ESX94ZH998NFEDYWWZ3KPB","verify-this","Verify a claim with fresh local evidence: restate it falsifiably, capture baseline and treatment, compare artifacts, and return VERIFIED, NOT VERIFIED, or INCONCLUSIVE.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fverify-this\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fverify-this\u002FSKILL.md",[],[],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":80,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":20},"01M7ESWN09M3H3BXEW47JAWS54","unslop","Cut AI tells from any writing.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Funslop\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Funslop\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":88,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":20},"01M7ESW6JKSZKCT7W24WD39JG0","technical-writing","Layered technical-writing standard: Diátaxis structure, Google developer style sentences, STE instruction rules, Global English syntax. Use for \u002Ftechnical-writing or when writing or reviewing docs, RFCs, readmes, PR descriptions, or commit messages.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftechnical-writing\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftechnical-writing\u002FSKILL.md",[],[],{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":96,"sourceHtmlUrl":97,"categories":98,"keywords":99,"publishedAt":20},"01M7ESV5734KYK1R12T20KF8FC","tdd","Use only when the user explicitly asks for TDD, a failing test, or a regression test, OR when the bug has an obvious cheap local test target. Skip when the test path is unclear, expensive, integration-heavy, or not requested.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftdd\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Ftdd\u002FSKILL.md",[],[],{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":104,"sourceHtmlUrl":105,"categories":106,"keywords":107,"publishedAt":20},"01M7EST4EVXXWVC8VAGV4XETT5","swarm","Fan out N parallel workers, drain them, and return one report. Use for \u002Fswarm, 'swarm this', or parallel coverage, races, gauntlets, and exploration.","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fswarm\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fvultuk\u002Fskills-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fpstack\u002Fskills\u002Fswarm\u002FSKILL.md",[],[]]