
migrate-better-result-3
Migrate a TypeScript codebase from better-result 2.x to 3.0. Use when upgrading better-result across the TaggedError syntax, removed Result serialization helpers, recovery inference, matching, or retry APIs.
- Installs
- 55
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/dmmulroy/better-result --skill migrate-better-result-3- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads migrate-better-result-3 automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Migrate better-result to 3.0
Treat the compiler as the migration ledger: inventory first, make mechanical changes, then resolve each remaining error by API branch.
1. Establish the migration surface
Read repository instructions, package manifests, lockfiles, TypeScript configuration, and validation commands. Verify that the source version is better-result 2.x and inspect the installed 3.0 declarations when available; package source outranks remembered APIs.
Search production code and tests for:
rg -n --glob '*.{ts,tsx,mts,cts}' \
'TaggedError|Result\.(serialize|deserialize|hydrate|tryRecover|tryRecoverAsync|tryPromise|partition|gen)|matchError(Partial)?|TaggedErrorClass|Serialized(Result|Ok|Err)'
Classify every hit under the audited API changes in references/v3-api-diff.md. Include tests that structurally compare a Result containing a tagged error; tagged errors become iterable in v3 even though the Result.gen signature is unchanged. Record generated or vendored hits separately rather than editing them.
Complete when: the installed source version, target 3.0 API, validation commands, every matching production/test site, and every tagged-error Result assertion are accounted for by file and migration branch.
2. Apply the TaggedError codemod
List safe trailing-call edits:
node <skill-dir>/scripts/migrate-tagged-error-v3.mjs . --list
Review the listed class heritage expressions, then apply them:
node <skill-dir>/scripts/migrate-tagged-error-v3.mjs . --write
node <skill-dir>/scripts/migrate-tagged-error-v3.mjs . --check
The transform changes only the v2 class heritage shape:
class NotFoundError extends TaggedError("NotFoundError")<{ id: string }>() {}
// becomes
class NotFoundError extends TaggedError("NotFoundError")<{ id: string }> {}
It preserves constructors, properties, formatting, and call sites. Manually update exported TaggedErrorClass<Tag, Props> annotations to the v3 class type TaggedErrorClass<Tag>; move payload typing to the subclass application shown above.
Complete when: the script's check exits successfully and searches find no v2 trailing factory calls or two-argument TaggedErrorClass uses outside generated/vendor code.
3. Replace removed serialization helpers
If the inventory contains Result.serialize, Result.deserialize, or Result.hydrate, follow references/result-codec-migration.md. The owning codec validates one application contract: a method's actual Ok and Err payloads in both directions. Share schema fragments, factories, and error-policy helpers across codecs; keep distinct success contracts in distinct named codecs.
Account for changed control flow: serialization can now return ResultSerializationError; deserialization adds ResultDeserializationError; sync/async schemas determine whether codec operations return a Result or Promise<Result>. When the repository owns both producer and consumer, versions their schemas together, and treats contract mismatch as a defect, prefer serializeUnsafe and deserializeUnsafe to remove codec-error handling boilerplate. serializeUnsafe removes ResultSerializationError by panicking; deserializeUnsafe removes only ResultDeserializationError while preserving valid decoded domain Err values. Keep safe methods at public, independently versioned, persisted, or otherwise untrusted boundaries.
Complete when: every removed-helper call has a method- or boundary-specific codec with four payload schemas, every wire Err is reconstructed as the intended domain error, and every codec error or intentional unsafe Panic policy and async return is handled at its boundary.
4. Reconcile changed inference and optional APIs
Type-check after the mechanical and codec changes. Resolve diagnostics using references/v3-api-diff.md, especially:
tryRecoverandtryRecoverAsyncnow preserve the original success and union it with a different recovered success type.matchError,matchErrorPartial, and the additiveTaggedError#matchmethod infer unions from divergent handler returns. Exhaustive matching turns thrown handlers intoPanic;matchis reserved, so rename payload or subclass collisions rejected by the v3 types.matchErrorPartialmay omit its fallback; an unhandled tagged error is then returned unchanged.Result.partitionnow supports heterogeneous inputs;all,allAsync, andpartitionAsyncare new.Result.tryPromiseadds abort context, dynamic delays, and jitter while retaining valid v2 static retry configurations.- Tagged errors are iterable for direct
yield*inResult.gen. Replace structural deep-equality assertions over tagged errors with separate Result-status and error identity/field assertions.
Keep existing runtime behavior unless the user requested adoption of a new 3.0 capability. Prefer accurate widened types and explicit narrowing over casts.
Complete when: every compiler diagnostic caused by a changed 3.0 signature is resolved, every intentional inferred union reaches an explicit handling point, and unrelated behavior remains unchanged.
5. Upgrade and prove the migration
Update the direct dependency and lockfile to the exact requested stable or prerelease 3.0 version. Keep that version fixed while diagnosing migration behavior.
Run one targeted migrated test first. Read the package script and package-manager argument-passthrough rules, then verify the runner's collected-file output contains only the intended test files. Run formatting, lint, type-check, the full test suite, and build commands required by the repository. Repeat the inventory search and the codemod check. Preserve unrelated files when a repository-wide formatter reports pre-existing failures.
Report the version change, files migrated by branch, codec/error-handling decisions, adopted optional features, and validation evidence.
Complete when: the targeted run exercised only its intended files, no removed API or v2 TaggedError syntax remains outside recorded generated/vendor code, all inventoried sites are closed, the requested version is still installed, and every repository check passes or has a concrete reported failure.
FAQ
What does the migrate-better-result-3 skill do?
Migrate a TypeScript codebase from better-result 2.x to 3.0. Use when upgrading better-result across the TaggedError syntax, removed Result serialization helpers, recovery inference, matching, or retry APIs.
How do I install migrate-better-result-3?
Run npx skills add https://github.com/dmmulroy/better-result --skill migrate-better-result-3 in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/migrate-better-result-3/ (personal) or .claude/skills/migrate-better-result-3/ (project).
Which AI agents can use migrate-better-result-3?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is migrate-better-result-3 safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains migrate-better-result-3?
It is published by dmmulroy in dmmulroy/better-result. It has 55 recorded installs.
More from dmmulroy/better-result
better-result-adopt
dmmulroy/better-result
Adopt better-result in an existing TypeScript codebase. Use when replacing try/catch, Promise rejection handling, null sentinels, or thrown domain exceptions with typed Result workflows.
adopt-better-result
dmmulroy/better-result
Adopt better-result in an existing TypeScript codebase. Use for a repository-wide error-handling audit and proposal, or for implementing a named vertical slice with TaggedError and Result.
better-result-migrate-v2
dmmulroy/better-result
Migrate better-result TaggedError usage from the v1 class-based API to the v2 factory-based API. Use when upgrading a codebase that still extends TaggedError directly or calls the old static helpers.
Popular code quality & workflow skills
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
improve-codebase-architecture
mattpocock/skills
Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.
handoff
mattpocock/skills
Compact the current conversation into a handoff document for another agent to pick up.
domain-modeling
mattpocock/skills
Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.
codebase-design
mattpocock/skills
Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
diagnosing-bugs
mattpocock/skills
Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.