{"id":20374,"plugin_id":"plugins_6aa30aa10cf88191bb67ad3007e43fdc","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:16:13.081Z","digest":"f48be1ec7c6eaf99f1a75053d214c1b01104cebb97c4ff83480e8fb14dd08e9a","against":null,"payload":{"name":"migrate-to-shoehorn","description":"Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.","included_files":[{"relative_path":"agents/openai.yaml","size_in_bytes":110}],"skill_md_contents":"---\nname: migrate-to-shoehorn\ndescription: Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.\ndisable-model-invocation: true\n---\n\n# Migrate to Shoehorn\n\n## Why shoehorn?\n\n`shoehorn` lets you pass partial data in tests while keeping TypeScript happy. It replaces `as` assertions with type-safe alternatives.\n\n**Test code only.** Never use shoehorn in production code.\n\nProblems with `as` in tests:\n\n- Trained not to use it\n- Must manually specify target type\n- Double-as (`as unknown as Type`) for intentionally wrong data\n\n## Install\n\n```bash\nnpm i @total-typescript/shoehorn\n```\n\n## Migration patterns\n\n### Large objects with few needed properties\n\nBefore:\n\n```ts\ntype Request = {\n  body: { id: string };\n  headers: Record<string, string>;\n  cookies: Record<string, string>;\n  // ...20 more properties\n};\n\nit(\"gets user by id\", () => {\n  // Only care about body.id but must fake entire Request\n  getUser({\n    body: { id: \"123\" },\n    headers: {},\n    cookies: {},\n    // ...fake all 20 properties\n  });\n});\n```\n\nAfter:\n\n```ts\nimport { fromPartial } from \"@total-typescript/shoehorn\";\n\nit(\"gets user by id\", () => {\n  getUser(\n    fromPartial({\n      body: { id: \"123\" },\n    }),\n  );\n});\n```\n\n### `as Type` → `fromPartial()`\n\nBefore:\n\n```ts\ngetUser({ body: { id: \"123\" } } as Request);\n```\n\nAfter:\n\n```ts\nimport { fromPartial } from \"@total-typescript/shoehorn\";\n\ngetUser(fromPartial({ body: { id: \"123\" } }));\n```\n\n### `as unknown as Type` → `fromAny()`\n\nBefore:\n\n```ts\ngetUser({ body: { id: 123 } } as unknown as Request); // wrong type on purpose\n```\n\nAfter:\n\n```ts\nimport { fromAny } from \"@total-typescript/shoehorn\";\n\ngetUser(fromAny({ body: { id: 123 } }));\n```\n\n## When to use each\n\n| Function        | Use case                                           |\n| --------------- | -------------------------------------------------- |\n| `fromPartial()` | Pass partial data that still type-checks           |\n| `fromAny()`     | Pass intentionally wrong data (keeps autocomplete) |\n| `fromExact()`   | Force full object (swap with fromPartial later)    |\n\n## Workflow\n\n1. **Gather requirements** - ask user:\n   - What test files have `as` assertions causing problems?\n   - Are they dealing with large objects where only some properties matter?\n   - Do they need to pass intentionally wrong data for error testing?\n\n2. **Install and migrate**:\n   - [ ] Install: `npm i @total-typescript/shoehorn`\n   - [ ] Find test files with `as` assertions: `grep -r \" as [A-Z]\" --include=\"*.test.ts\" --include=\"*.spec.ts\"`\n   - [ ] Replace `as Type` with `fromPartial()`\n   - [ ] Replace `as unknown as Type` with `fromAny()`\n   - [ ] Add imports from `@total-typescript/shoehorn`\n   - [ ] Run type check to verify\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}