migrate-to-shoehorn · v1.0 · 2026-05-04 · sha256 be8ada808ccc25eb
migrate-to-shoehorn v1.0A
Immutable. This exact content is served forever at /api/v1/blob/be8ada808ccc25eb.
---
name: migrate-to-shoehorn
description: >
Migrate TypeScript test files from unsafe `as` type assertions to type-safe
alternatives from @total-typescript/shoehorn. Replace `obj as Type` with
fromPartial(), `obj as unknown as Type` with fromAny(), and complete specs
with fromExact(). Test code only — never use in production.
allowed-tools: Read Grep Glob Bash Write Edit
compatibility: >
TypeScript projects only. Test code exclusively — production usage is prohibited.
Requires npm install @total-typescript/shoehorn. Pairs with testing-strategies
and backend-testing for broader test quality work.
metadata:
tags: typescript, testing, type-safety, assertions, migration, shoehorn
platforms: Claude, ChatGPT, Gemini, Codex
version: "1.0"
source: mattpocock/skills
---
# Migrate to Shoehorn
Replace unsafe TypeScript `as` assertions in test files with type-safe alternatives from `@total-typescript/shoehorn`.
## When to use this skill
- Modernizing test code to eliminate `as` type assertion anti-patterns
- Making test data creation type-safe with autocomplete support
- Migrating from `as unknown as Type` double-assertions
## When not to use this skill
- Production code (shoehorn is **test code only**)
- Non-TypeScript projects
- Runtime type validation → use a library like `zod`
## Installation
```bash
npm i @total-typescript/shoehorn
```
## The three functions
### `fromPartial<T>(partial)` — incomplete objects
Use when you only need a few properties of a large type:
```typescript
// Before (unsafe)
const user = { name: "Alice" } as User
// After (type-safe, keeps autocomplete)
import { fromPartial } from "@total-typescript/shoehorn"
const user = fromPartial<User>({ name: "Alice" })
```
### `fromAny<T>(value)` — intentionally wrong data
Use when testing with deliberately incorrect data (error cases, edge cases):
```typescript
// Before (verbose double-as)
const badInput = { invalid: true } as unknown as User
// After
import { fromAny } from "@total-typescript/shoehorn"
const badInput = fromAny<User>({ invalid: true })
```
### `fromExact<T>(complete)` — enforced complete objects
Use when the test requires a fully-specified object (no missing fields):
```typescript
// Before
const user = { name: "Alice", email: "alice@example.com", id: 1 } as User
// After (TypeScript will error if any field is missing)
import { fromExact } from "@total-typescript/shoehorn"
const user = fromExact<User>({ name: "Alice", email: "alice@example.com", id: 1 })
```
## Migration workflow
### 1. Find all `as` assertions in test files
```bash
grep -rn " as " --include="*.test.ts" --include="*.spec.ts" --include="*.test.tsx"
```
### 2. Classify each assertion
- Partial object, only some fields needed → `fromPartial()`
- Intentionally wrong/invalid data → `fromAny()`
- Complete object, all fields present → `fromExact()`
### 3. Replace and add import
```typescript
import { fromPartial, fromAny, fromExact } from "@total-typescript/shoehorn"
```
### 4. Verify TypeScript still compiles
```bash
npx tsc --noEmit
```
## Critical constraint
**Test code only.** Never use `fromPartial`, `fromAny`, or `fromExact` in production code. These functions bypass type safety for testing purposes only.