VanaAPI

← Writing

Moving one JavaScript module to TypeScript

Daily workEN2026-10-26

Start with one module, not a repository-wide conversion. For this walkthrough, choose a JavaScript utility that reads an API response and prepares records for display. The goal is deliberately narrow: introduce useful types without changing what callers receive. Ask the model for small patches, then check each patch against the compiler and existing behavior.

§ Step 1: Record the starting behavior

Create a branch and run the current tests, lint command, and production build. Record any failures before editing. Choose a module with a few callers and tests you can understand without reading the entire application.

If coverage is thin, add characterization tests first. For a response formatter, cover an empty list, a missing optional field, and a malformed record. Review the expected results yourself rather than letting the model decide what the application should do.

§ Step 2: Give the model a bounded assignment

Provide the module, its direct callers, relevant tests, package configuration, and build settings. Remove credentials and private production data. Ask for a plan before requesting edits:

Suggested prompt: “Plan the migration of this module to TypeScript. Preserve exports, runtime behavior, and module conventions. Identify uncertain input shapes. Do not edit unrelated files or upgrade dependencies. List assumptions before proposing a patch.”

For the model connection, Vana API supports existing coding workflows through client-specific protocol paths, including OpenAI-compatible clients and Gemini CLI. Follow the configuration for your chosen client rather than assuming every tool uses an identical path. Create a Vana API account if you want to use that connection for the walkthrough. ([vanaapi.com](https://vanaapi.com/))

§ Step 3: Prepare a mixed-language project

Install TypeScript as a development dependency if it is not already present. Ask the model to propose the smallest configuration change compatible with your existing build. Enable allowJs so JavaScript and TypeScript files can coexist during the migration. ([typescriptlang.org](https://www.typescriptlang.org/tsconfig/allowJs.html))

Keep checkJs disabled initially if checking every included JavaScript file would expand the task. Enable checking selectively with a file-level // @ts-check comment when useful, or enable checkJs when you intentionally want diagnostics across included JavaScript files. ([typescriptlang.org](https://www.typescriptlang.org/tsconfig/checkJs.html))

If the existing build tool already transforms TypeScript, use noEmit for the compiler’s checking pass. It prevents TypeScript from generating output files; it does not configure the application’s build tool for you. ([typescriptlang.org](https://www.typescriptlang.org/tsconfig/noEmit.html))

§ Step 4: Convert the smallest useful unit

Ask the model to rename the selected file from .js to .ts and annotate its public boundary. Require it to preserve export names, default values, exception behavior, and synchronous or asynchronous execution. Review the patch before accepting it.

Suggested prompt: “Convert only this module. Derive parameter and return types from the supplied implementation, callers, and tests. Flag conflicting evidence. Do not invent guarantees about external data.”

Prefer readable object types and unions over elaborate abstractions. Avoid accepting broad any annotations merely to silence errors: any disables further type checking for the affected values. ([typescriptlang.org](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html))

§ Step 5: Review external data separately

Inspect every place where the module receives network responses, stored JSON, or user input. Separate the shape your application expects from the evidence that incoming data actually has that shape.

A type assertion does not validate a response at runtime; assertions are removed during compilation. If the migration exposes a missing validation step, document it and decide explicitly whether to add validation in a separate patch. Do not disguise a behavior change as a typing fix. ([typescriptlang.org](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html))

§ Step 6: Feed back diagnostics, not guesses

Run the project’s type-check command, tests, lint, and build. Give the model the exact diagnostics and only the surrounding files needed to explain them. Request the smallest correction, not a general cleanup.

Reject patches that weaken compiler settings, delete failing tests, or add unexplained suppressions. Re-run the checks after each accepted correction.

§ Step 7: Commit a repeatable boundary

Review the final diff for unrelated edits and confirm the original callers still behave as expected. Commit the converted module, necessary configuration, and tests together. Then choose the next neighboring module. Keep each migration small enough that a reviewer can explain both the new types and the behavior left unchanged.