By default Claude Code struggles to port JavaScript to TypeScript. Often the types it generates are filled with usages of any or inline cast like x as unknown as { bleh(): void }. In the worst cases it abandons entire files and inserts @ts-nocheck disabling typechecking for those files altogether.
The problem is Claude Code prioritizes a passing typecheck after every single edit. It treats a successful tsc run as a strict requirement; if a cast is the quickest way to resolve an immediate error, it will use one. Each edit is locally successful but the overall result is poor. This leads to a codebase cluttered with any and as unknown as.
This is the wrong approach. Effective typing requires knowledge about the shared architecture of a program not just reacting to typecheck errors from tsc.
Two Pass Workflow
The solution is straightforward: port the codebase in two passes and prevent Claude from running tsc during the first pass. By removing the immediate requirement for a successful typecheck we force Claude Code to focus on designing types from its own reasoning rather then simply silencing errors.
- Pass 1: Add types: Claude is forced to add type annotations without invoking tsc, forcing it to build the types entirely from its own reasoning and the context window it creates by scanning the codebase.
- Pass 1.5: Coherence Review: Claude reviews the ported files for global type coherency. Typechecking is still disabling.
- Pass 2: Resolving Errors (Typechecker Enabled). Only now does Claude run
tscand resolve (any remaining) type errors.
Hard Limits
It’s also useful to set a few hard limits for claude code:
- No use of
unknownoranyduring phase 1 and 1.5 at all. anylimited to X usages across the entire codebase for pass 2.- Enable
strictNullChecksfrom the beginning.
Establish a Testing Baseline
It’s important to make sure the old JS codebase has adequate unit tests. You can have Claude Code generate these for you, e.g.: First, review the core logic in [target file/directory] and generate a comprehensive suite of unit tests for the existing JavaScript. Ensure the tests pass. Once established, use the js-to-ts-port skill to port the code to TypeScript, using the test suite to verify the logic remains intact.
I have packaged this methodology as a Claude Code skill: js-to-ts-port.
