Refactor TypeScript 'as' assertions in tests to use @total-typescript/shoehorn helpers.
Install
mkdir -p .claude/skills/migrate-to-shoehorn-jupes && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16476" && unzip -o skill.zip -d .claude/skills/migrate-to-shoehorn-jupes && rm skill.zipInstalls to .claude/skills/migrate-to-shoehorn-jupes
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Migrate test files from `as` assertions to @total-typescript/shoehorn helpers. Use when tests need partial fixtures, intentionally invalid data, or safer replacements for TypeScript assertions.Key capabilities
- →Migrate test files from `as` assertions to `@total-typescript/shoehorn` helpers
- →Replace `value as Type` with `fromPartial(value)` for partial fixtures
- →Replace `value as unknown as Type` with `fromAny(value)` for intentionally invalid data
- →Use `fromExact(value)` for full-shape fixtures during migration
- →Install `@total-typescript/shoehorn` using the repository's package manager
How it works
This skill identifies `as` assertions in test files and replaces them with `@total-typescript/shoehorn` helpers like `fromPartial()`, `fromAny()`, or `fromExact()`, based on the assertion's intent. It also handles package installation.
Inputs & outputs
When to use migrate-to-shoehorn
- →Refactor large test objects
- →Replace 'as unknown as Type' casts
- →Clean up test fixtures
About this skill
migrate-to-shoehorn
Use this skill to migrate test code only from TypeScript as assertions to @total-typescript/shoehorn helpers.
Shoehorn is for tests, fixtures, and test-only helpers. Do not recommend it for production or source files, and do not add @total-typescript/shoehorn imports outside *.test.* or *.spec.* files.
When To Use
- A test creates a large object but only needs a few properties.
- A test uses
value as Typeto satisfy a function, component, or hook signature. - A test intentionally passes invalid data and currently uses
value as unknown as Type. - A fixture needs a temporary full-shape wrapper while it is being migrated.
Do not use this skill to loosen production typing. If the assertion is in source code, fix the domain type, parser, or test boundary instead.
Install
Install Shoehorn only when the target repository does not already depend on it, and use the package manager already used by that repository:
# bun.lock or bun.lockb
bun add -d @total-typescript/shoehorn
# pnpm-lock.yaml
pnpm add -D @total-typescript/shoehorn
# yarn.lock
yarn add -D @total-typescript/shoehorn
# package-lock.json or npm-shrinkwrap.json
npm install --save-dev @total-typescript/shoehorn
Do not switch package managers. If multiple lockfiles exist, ask which package manager owns the repo before installing.
Find Candidate Tests
Search only test files and review every result manually:
rg "\bas\s+[A-Z][A-Za-z0-9_$]*(<[^>]+>)?" --glob "*.{test,spec}.{ts,tsx}"
rg "\bas\s+unknown\s+as\s+" --glob "*.{test,spec}.{ts,tsx}"
Avoid broad replacements. Migrate one assertion at a time so the new helper matches the test intent.
Migration Patterns
value as Type -> fromPartial(value)
Use fromPartial() when the test supplies a subset of a larger type and the supplied properties should still type-check.
Before:
getUser({ body: { id: "123" } } as Request);
After:
import { fromPartial } from "@total-typescript/shoehorn";
getUser(fromPartial({ body: { id: "123" } }));
If TypeScript cannot infer the target from context, provide the target type explicitly:
const request = fromPartial<Request>({
body: { id: "123" },
});
value as unknown as Type -> fromAny(value)
Use fromAny() only when the test intentionally passes invalid data, such as exercising validation or error handling paths. This replaces double assertions while keeping the intent visible.
Before:
getUser({ body: { id: 123 } } as unknown as Request);
After:
import { fromAny } from "@total-typescript/shoehorn";
getUser(fromAny({ body: { id: 123 } }));
Full-Shape Fixtures -> fromExact(value)
Use fromExact() as a temporary helper when a fixture already has the full shape and you want to keep the migration mechanical before deciding whether it can be reduced.
import { fromExact } from "@total-typescript/shoehorn";
const request = fromExact<Request>({
body: { id: "123" },
headers: {},
cookies: {},
});
Prefer fromPartial() once the test only needs a subset of the object. fromExact() should not become a dumping ground for unnecessary fixture fields.
Workflow
- Confirm the target files are tests (
*.test.ts,*.test.tsx,*.spec.ts, or*.spec.tsx). - Check whether
@total-typescript/shoehornis already installed. - If installation is needed, use the existing package manager from the repo lockfile.
- Search for candidate assertions with the
rgcommands above. - Replace
value as TypewithfromPartial(value)when the supplied data is partial but type-valid. - Replace
value as unknown as TypewithfromAny(value)when the supplied data is intentionally invalid. - Use
fromExact()only for full-shape fixtures or short-lived migration steps. - Add the narrowest import needed from
@total-typescript/shoehorn. - Run the target test file, the repo test suite, and the typecheck command.
Validation
After migrating, run the repository's normal checks. For a Bun-based repo, use:
bun run typecheck
bun test
Verify Shoehorn remains test-only:
rg "@total-typescript/shoehorn"
rg "@total-typescript/shoehorn" --glob "!*.{test,spec}.{ts,tsx}"
The first command should show only intended test imports. The second command should return no source-file imports; if it finds any, remove Shoehorn from production/source code and fix the underlying type boundary instead.
When not to use it
- →Loosening production typing
- →Assertions in source code (non-test files)
- →When the assertion is not in `*.test.*` or `*.spec.*` files
Limitations
- →Use this skill to migrate test code only.
- →Do not recommend `@total-typescript/shoehorn` for production or source files.
- →Avoid broad replacements; migrate one assertion at a time.
How it compares
This skill automates the refactoring of TypeScript `as` assertions in test code to specialized helpers, improving type safety and readability in tests, unlike manual refactoring or general type-checking tools.
Compared to similar skills
migrate-to-shoehorn side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| migrate-to-shoehorn (this skill) | 0 | 3mo | Review | Intermediate |
| tdd-workflow | 6 | 4mo | Review | Intermediate |
| migrate | 1 | 5mo | Review | Intermediate |
| agent-implementer-sparc-coder | 1 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
tdd-workflow
affaan-m
在编写新功能、修复错误或重构代码时使用此技能。强制执行测试驱动开发,包含单元测试、集成测试和端到端测试,覆盖率超过80%。
migrate
alirezarezvani
Migrate from Cypress or Selenium to Playwright. Use when user mentions "cypress", "selenium", "migrate tests", "convert tests", "switch to playwright", "move from cypress", or "replace selenium".
agent-implementer-sparc-coder
ruvnet
Agent skill for implementer-sparc-coder - invoke with $agent-implementer-sparc-coder
tdd-migrate
parcadei
TDD workflow for migrations - orchestrate agents, zero main context growth
migrate-to-shoehorn
amazingloft999-droid
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.
react18-enzyme-to-rtl
ArryoRuma
Provides exact Enzyme → React Testing Library migration patterns for React 18 upgrades. Use this skill whenever Enzyme tests need to be rewritten - shallow, mount, wrapper.find(), wrapper.simulate(), wrapper.prop(), wrapper.state(), wrapper.instance(), Enzyme configure/Adapter calls, or any test fil