---
id: daily-migrate-to-shoehorn
name: "migrate-to-shoehorn"
url: https://skills.yangsir.net/skill/daily-migrate-to-shoehorn
author: mattpocock
domain: testing
tags: ["testing", "typescript", "type-safety", "test-automation", "code-quality"]
install_count: 471200
rating: 4.90 (22 reviews)
github: https://github.com/mattpocock/skills
---

# migrate-to-shoehorn

> 将测试代码中的TypeScript as断言替换为类型安全的shoehorn模式，提升测试可维护性和类型安全性

**Stats**: 471,200 installs · 4.9/5 (22 reviews)

## Before / After 对比

### 测试类型安全

**Before**:

使用as断言时类型错误被掩盖，测试通过但运行时崩溃，排查困难且耗时

**After**:

shoehorn提供类型安全替代方案，编译期捕获类型错误，测试更可靠可维护

| Metric | Before | After | Change |
|---|---|---|---|
| 类型错误率 | 15% | 2% | -87% |

## Readme

# migrate-to-shoehorn

# Migrate to Shoehorn

## Why shoehorn?

`shoehorn` lets you pass partial data in tests while keeping TypeScript happy. It replaces `as` assertions with type-safe alternatives.

**Test code only.** Never use shoehorn in production code.

Problems with `as` in tests:

- Trained not to use it

- Must manually specify target type

- Double-as (`as unknown as Type`) for intentionally wrong data

## Install

```
npm i @total-typescript/shoehorn

```

## Migration patterns

### Large objects with few needed properties

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 purpose

```

After:

```
import { fromAny } from "@total-typescript/shoehorn";

getUser(fromAny({ body: { id: 123 } }));

```

## When to use each

Function
Use case

`fromPartial()`
Pass partial data that still type-checks

`fromAny()`
Pass intentionally wrong data (keeps autocomplete)

`fromExact()`
Force full object (swap with fromPartial later)

## Workflow

- 

**Gather requirements** - ask user:

What test files have `as` assertions causing problems?

- Are they dealing with large objects where only some properties matter?

- Do they need to pass intentionally wrong data for error testing?

- 

**Install and migrate**:

 Install: `npm i @total-typescript/shoehorn`

-  Find test files with `as` assertions: `grep -r " as [A-Z]" --include="*.test.ts" --include="*.spec.ts"`

-  Replace `as Type` with `fromPartial()`

-  Replace `as unknown as Type` with `fromAny()`

-  Add imports from `@total-typescript/shoehorn`

-  Run type check to verify

Weekly Installs279Repository[mattpocock/skills](https://github.com/mattpocock/skills)GitHub Stars4.6KFirst SeenFeb 13, 2026Security Audits[Gen Agent Trust HubFail](/mattpocock/skills/migrate-to-shoehorn/security/agent-trust-hub)[SocketPass](/mattpocock/skills/migrate-to-shoehorn/security/socket)[SnykPass](/mattpocock/skills/migrate-to-shoehorn/security/snyk)Installed onopencode260codex257gemini-cli256github-copilot251kimi-cli250amp250

---
*Source: https://skills.yangsir.net/skill/daily-migrate-to-shoehorn*
*Markdown mirror: https://skills.yangsir.net/api/skill/daily-migrate-to-shoehorn/markdown*