/migrate-to-shoehorn
将测试文件从 `as` 类型断言迁移到 @total-typescript/shoehorn。适用于用户提到 shoehorn、想替换测试中的 `as`,或需要局部测试数据时。
Claude Code
$ npx -y skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn --agent claude-code
Codex
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a codex -y
Cursor
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a cursor -y
Gemini CLI
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a gemini-cli -y
GitHub Copilot
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a github-copilot -y
OpenCode
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a opencode -y
Windsurf
$ npx skills add vinvcn/mattpocock-skills-zh-cn --skill migrate-to-shoehorn -a windsurf -y
SKILL.md
migrate-to-shoehorn.SKILL.mdname: migrate-to-shoehorn
description: 将测试文件从 `as` 类型断言迁移到 @total-typescript/shoehorn。适用于用户提到 shoehorn、想替换测试中的 `as`,或需要局部测试数据时。
迁移到 Shoehorn
为什么用 shoehorn?
`shoehorn` 允许你在 tests 中传入 partial data,同时保持 TypeScript 满意。它用 type-safe alternatives 替换 `as` assertions。
**只用于 test code。** 永远不要在 production code 中使用 shoehorn。
Tests 中 `as` 的问题:
- 经过训练,不去使用它
- 必须手动指定 target type
- 对故意错误的数据需要 double-as(`as unknown as Type`)
安装
npm i @total-typescript/shoehorn
迁移模式
只需要少数属性的大型 objects
Before:
type Request = {
body: { id: string };
headers: Record<string, string>;
cookies: Record<string, string>;
// ...20 more properties
};
it("gets user by id", () => {
// Only care about body.id but must fake entire Request
getUser({
body: { id: "123" },
headers: {},
cookies: {},
// ...fake all 20 properties
});
});After:
import { fromPartial } from "@total-typescript/shoehorn";
it("gets user by id", () => {
getUser(
fromPartial({
body: { id: "123" },
}),
);
});`as Type` → `fromPartial()`
Before:
getUser({ body: { id: "123" } } as Request);After:
import { fromPartial } from "@total-typescript/shoehorn";
getUser(fromPartial({ body: { id: "123" } }));`as unknown as Type` → `fromAny()`
Before:
getUser({ body: { id: 123 } } as unknown as Request); // wrong type on purposeAfter:
import { fromAny } from "@total-typescript/shoehorn";
getUser(fromAny({ body: { id: 123 } }));何时使用哪一个
| Function | Use case | | --------------- | -------------------------------------------------- | | `fromPartial()` | 传入仍能 type-check 的 partial data | | `fromAny()` | 传入故意错误的数据(保留 autocomplete) | | `fromExact()` | 强制 full object(之后可换成 fromPartial) |
工作流
1. **Gather requirements** - 询问用户:
- 哪些 test files 中的 `as` assertions 造成问题?
- 是否在处理大型 objects,但只关心部分 properties?
- 是否需要传入故意错误的数据来测试 error paths?
2. **Install and migrate**:
- [ ] Install: `npm i @total-typescript/shoehorn`
- [ ] 查找 test files 中的 `as` assertions: `grep -r " as [A-Z]" --include="*.test.ts" --include="*.spec.ts"`
- [ ] 用 `fromPartial()` 替换 `as Type`
- [ ] 用 `fromAny()` 替换 `as unknown as Type`
- [ ] 添加来自 `@total-typescript/shoehorn` 的 imports
- [ ] 运行 type check 验证
Read more
name: migrate-to-shoehorn description: 将测试文件从 `as` 类型断言迁移到 @total-typescript/shoehorn。适用于用户提到 shoehorn、想替换测试中的 `as`,或需要局部测试数据时。
迁移到 Shoehorn
为什么用 shoehorn?
`shoehorn` 允许你在 tests 中传入 partial data,同时保持 TypeScript 满意。它用 type-safe alternatives 替换 `as` assertions。
**只用于 test code。** 永远不要在 production code 中使用 shoehorn。
Tests 中 `as` 的问题:
- 经过训练,不去使用它
- 必须手动指定 target type
- 对故意错误的数据需要 double-as(`as unknown as Type`)
安装
npm i @total-typescript/shoehorn
迁移模式
只需要少数属性的大型 objects
Before:
type Request = {
body: { id: string };
headers: Record<string, string>;
cookies: Record<string, string>;
// ...20 more properties
};
it("gets user by id", () => {
// Only care about body.id but must fake entire Request
getUser({
body: { id: "123" },
headers: {},
cookies: {},
// ...fake all 20 properties
});
});After:
import { fromPartial } from "@total-typescript/shoehorn";
it("gets user by id", () => {
getUser(
fromPartial({
body: { id: "123" },
}),
);
});`as Type` → `fromPartial()`
Before:
getUser({ body: { id: "123" } } as Request);After:
import { fromPartial } from "@total-typescript/shoehorn";
getUser(fromPartial({ body: { id: "123" } }));`as unknown as Type` → `fromAny()`
Before:
getUser({ body: { id: 123 } } as unknown as Request); // wrong type on purposeAfter:
import { fromAny } from "@total-typescript/shoehorn";
getUser(fromAny({ body: { id: 123 } }));何时使用哪一个
| Function | Use case | | --------------- | -------------------------------------------------- | | `fromPartial()` | 传入仍能 type-check 的 partial data | | `fromAny()` | 传入故意错误的数据(保留 autocomplete) | | `fromExact()` | 强制 full object(之后可换成 fromPartial) |
工作流
1. **Gather requirements** - 询问用户:
- 哪些 test files 中的 `as` assertions 造成问题?
- 是否在处理大型 objects,但只关心部分 properties?
- 是否需要传入故意错误的数据来测试 error paths?
2. **Install and migrate**:
- [ ] Install: `npm i @total-typescript/shoehorn`
- [ ] 查找 test files 中的 `as` assertions: `grep -r " as [A-Z]" --include="*.test.ts" --include="*.spec.ts"`
- [ ] 用 `fromPartial()` 替换 `as Type`
- [ ] 用 `fromAny()` 替换 `as unknown as Type`
- [ ] 添加来自 `@total-typescript/shoehorn` 的 imports
- [ ] 运行 type check 验证
Matt Pocock 的 mattpocock/skills:第三方简体中文本地化,非官方仓库。这些 agent skills 是他每天用于真实工程工作的,不是 vibe coding:小、易改、可组合,适用于任何模型。 本仓库定期同步上游,并额外支持 DeepSeek Harness(dsh)插件安装,安装后以 /zh- 调用任意技能(上游没有的能力,详见 dsh-plugin/README.md)。
Other skills on vinvcn-mattpocock-skills.
code-review
从固定点(commit、branch、tag 或 merge-base)开始,按 Standards(代码是否符合本仓库记录的编码标准?)和 Spec(代码是否符合来源 issue/spec…
codebase-design
用于设计深模块的共享词汇。适用于用户想设计或改进模块接口、寻找深化机会、决定 seam 放在哪里、让代码更容易测试或更适合 AI 导航,或其他技能需要深模块词汇时。
diagnosing-bugs
面向棘手缺陷和性能回退的诊断循环。适用于用户说 “diagnose” / “debug this”,或报告某些东西 broken、throwing、failing、slow 时。
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about migrate-to-shoehorn.
- Which coding agents can use migrate-to-shoehorn?
- migrate-to-shoehorn installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

