[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71RYJ6JZJZ067VDF2BGC5VD":3,"skill-same:01M71RYJ6JZJZ067VDF2BGC5VD":70},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":35,"linkOnly":36,"markdownContent":37,"markdownBody":38,"frontMatter":39,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":50,"install":51,"resources":63},"01M71RYJ6JZJZ067VDF2BGC5VD","pstack-typescript-best-practices",null,"TypeScript best practices. Use when reading or editing any .ts or .tsx file.","dmae97\u002Fomk","dmae97","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F146327957?v=4","01M71RJRBWDNKEJ1A2DZVES8X1","01M71RJRCYHNT7E83M0Q42V6SJ",152,"MIT","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Fresources\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34],"typescript","best practices","typescript best practices","pstack","pstack typescript best practices","file","editing","use","tsx","reading","true","when","2026-11-10 13:02:02",false,"---\nname: pstack-typescript-best-practices\ndescription: TypeScript best practices. Use when reading or editing any .ts or .tsx file.\npaths: [\"**\u002F*.ts\", \"**\u002F*.tsx\"]\ndisable-model-invocation: true\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. A brand comes from a verifying type guard (`input is AgentId`), never from `as`. |\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. A brand comes from a verifying type guard (`input is AgentId`), never from `as`. |\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,"paths":40,"description":7,"disable-model-invocation":43},[41,42],"**\u002F*.ts","**\u002F*.tsx",true,"main","ea03fcf76b438f12f0cebcd6b255d24d4cb52741","packages\u002Fcoding-agent\u002Fresources\u002Fpstack\u002Fskills\u002Ftypescript-best-practices",29,"https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk","https:\u002F\u002Fgithub.com\u002Fdmae97","2026-11-12 14:25:52",{"source":8,"skillName":5,"commands":52,"prompt":62,"zipAvailable":43},[53,56,59],{"tool":54,"command":55},"npx","npx skills add dmae97\u002Fomk --skill pstack-typescript-best-practices",{"tool":57,"command":58},"bunx","bunx skills add dmae97\u002Fomk --skill pstack-typescript-best-practices",{"tool":60,"command":61},"pnpm","pnpm dlx skills add dmae97\u002Fomk --skill pstack-typescript-best-practices","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Fresources\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002FSKILL.md",[64],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"references\u002Fpatterns.md","REFERENCE","参考文档",9287,"https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Fresources\u002Fpstack\u002Fskills\u002Ftypescript-best-practices\u002Freferences\u002Fpatterns.md",[71,83,97,110,121,129],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":78,"publishedAt":35},"01M71RZKQCQ4G7MP08TE3QQ0PD","valid-skill","A valid skill for testing purposes.","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Fvalid-skill\u002FSKILL.md",[77],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[79,80,81,82],"valid skill","valid","testing","for",{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":90,"publishedAt":35},"01M71RZJ8YHH8GKADPTSZBCJ1T","unknown-field","A skill with an unknown frontmatter field.","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Funknown-field\u002FSKILL.md",[89],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[91,92,93,94,95,96],"unknown","unknown field","a skill","frontmatter","with","unknown frontmatter field",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":104,"publishedAt":35},"01M71RZH4FVEENABTV8WTQ5HTS","nested-child","Nested skill should be ignored.","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Froot-skill-preferred\u002Fnested-child\u002FSKILL.md",[103],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[105,106,107,108,109],"nested child","child","nested","ignored","nested skill",{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":117,"publishedAt":35},"01M71RZFZYSXRRVY5M8HP05NJV","root-skill-preferred","Root skill should win.","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Froot-skill-preferred\u002FSKILL.md",[116],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[118,119,120],"root","root skill preferred","root skill",{"skillNo":122,"name":123,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":127,"publishedAt":35},"01M71RZEQDH7RZ1PH36G7GPN9N","no-frontmatter","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Fno-frontmatter\u002FSKILL.md",[126],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[94,128],"no frontmatter",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":136,"publishedAt":35},"01M71RZDC0QR3ZJQ549N3H94Y4","child-skill","A nested skill in a subdirectory.","https:\u002F\u002Fgithub.com\u002Fdmae97\u002Fomk\u002Fblob\u002Fmain\u002Fpackages\u002Fcoding-agent\u002Ftest\u002Ffixtures\u002Fskills\u002Fnested\u002Fchild-skill\u002FSKILL.md",[135],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[137,106,109,107],"child skill"]