Skillsmigrate-to-shoehorn
M

migrate-to-shoehorn

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.

Migrate to Shoehorn — Replace as Assertions in Tests with a Type-Safe Approach

Skill Overview

This skill helps you migrate as type assertions in test files to @total-typescript/shoehorn, allowing tests to provide only partial data while still passing TypeScript type checks.

Applicable Scenarios

  1. Types have many properties, but the test only cares about one or two For example, a Request type may have more than twenty properties, such as body, headers, and cookies, while a test only uses body.id. Previously, you had to fake the entire object. With fromPartial(), you can provide only the fields you use and still pass type checking.

  2. You need to intentionally provide incorrectly typed data when testing error branches For example, when testing the error behavior for a body.id that should be a number. Previously, you could only write as unknown as Request. After migration, use fromAny() instead. This preserves editor autocomplete while clearly expressing that the incorrect type is intentional.

  3. Team conventions prohibit using as in tests and require bulk replacement This skill provides a complete checklist covering the process from searching and replacing to type checking, including grep commands and the one-to-one mapping between the three API types. It is suitable for migrating all test files in a repository at once.

Core Features

  1. fromPartial() — Provide partial data while retaining type safety Replaces as Type. The object only needs to include the properties the test actually cares about; you do not need to fill in every field of the target type. The return value is still treated as the complete target type.

  2. fromAny() — Provide intentionally incorrectly typed data Replaces as unknown as Type. It is used for error-branch tests, allowing values that do not conform to the type definition while retaining editor autocomplete.

  3. fromExact() — Require a complete object Requires all object fields to be present. It is suitable as an intermediate migration step: first use fromExact() to ensure completeness, then switch to fromPartial() as needed.

  4. A supporting migration workflow Includes installing dependencies, using grep -r " as [A-Z]" --include="*.test.ts" --include="*.spec.ts" to find all assertions, replacing them one by one, adding the necessary imports, and finally running type checks for verification.

Frequently Asked Questions

What is shoehorn, and what problem does it solve?

It is a testing utility library from @total-typescript. TypeScript tests frequently use as assertions: either to fake large objects with many properties or to intentionally provide incorrect data when testing error branches. The problem with as is that it bypasses type checking and requires you to manually write the target type. For intentionally incorrect cases, it also requires the double assertion as unknown as Type. Shoehorn replaces these patterns with three functions—fromPartial(), fromAny(), and fromExact()—so that partial data can pass type checking as well.

Can shoehorn be used in production code?

No. This skill is explicitly limited to test code only. Its purpose is to relax type requirements for test data. Using it in production code would open a hole in type checking within business logic, which goes against the reason for using it in the first place.

What is the difference between fromPartial and fromAny?

Use fromPartial() for partial but correctly typed data. The fields you provide are still type-checked, so misspelled field names or incorrect field types will produce errors. Use fromAny() for intentionally incorrectly typed data. Field types are no longer restricted, while editor autocomplete is retained. Simply put: use fromPartial() when you are providing fewer fields, and fromAny() when you are intentionally providing incorrect data.

Do I still need to specify all object properties when using fromPartial?

No. This is its primary benefit over as. You only need to write the fields the test actually uses; the remaining properties do not need to be fabricated. Conversely, if you want an object to include every field, use fromExact(), which reports an error when fields are missing.

What verification is required after migration?

You must run a type check. The migration involves removing many as assertions and adding imports, so only a successful type check can confirm that the replacements remain type-safe. This is also the final step in the skill checklist.