Skip to content

Convert codebase from JavaScript to TypeScript#693

Open
bfirsh wants to merge 2 commits intomainfrom
claude/convert-to-typescript-NWerJ
Open

Convert codebase from JavaScript to TypeScript#693
bfirsh wants to merge 2 commits intomainfrom
claude/convert-to-typescript-NWerJ

Conversation

@bfirsh
Copy link
Copy Markdown
Owner

@bfirsh bfirsh commented Apr 20, 2026

Summary

This PR converts the JSNES codebase from JavaScript to TypeScript, enabling better type safety and IDE support while maintaining backward compatibility. The conversion uses a "loose" approach with @ts-nocheck on most files to allow existing JavaScript patterns to continue working, with types added incrementally to the public API surface.

Key Changes

  • Source files: All .js files in src/ renamed to .ts with updated import statements to use .ts extensions
  • Type definitions: Removed separate .d.ts declaration files (nes.d.ts, controller.d.ts, browser.d.ts, gamegenie.d.ts) and integrated types directly into .ts source files
  • Public API types: Added comprehensive TypeScript interfaces and types for:
    • NES class: NESOptions, RomData, ControllerId, EmulatorData
    • Controller class: ButtonKey, ControllerState types and readonly static members
    • Browser class: BrowserOptions interface
    • GameGenie class: GameGeniePatch interface
  • Build configuration: Updated webpack to use ts-loader with transpileOnly: true for bundling TypeScript source
  • TypeScript config: Updated tsconfig.json to target ES2022, use nodenext module resolution, and allow importing .ts extensions
  • Test infrastructure: Tests remain as .js files but now import .ts source files directly; removed typedefs.spec.js test file (no longer needed with integrated types)
  • Package.json: Updated exports to point to .ts source for ESM imports; removed separate index.d.ts file
  • Documentation: Updated CLAUDE.md and README.md to reflect TypeScript usage

Implementation Details

  • Most internal files use // @ts-nocheck to allow loose JavaScript patterns during the conversion phase
  • Public API classes (NES, Controller, Browser, GameGenie) have full type annotations for method signatures and properties
  • Imports use explicit .ts extensions (e.g., import CPU from "./cpu.ts") to work with Node.js --experimental-strip-types
  • Build output (dist/jsnes.js, dist/jsnes.min.js) remains JavaScript for browser compatibility
  • Type checking via tsc --noEmit validates the public API surface
  • Webpack configuration simplified by removing ESLint plugin (linting handled separately)

https://claude.ai/code/session_019TZShVDgaieoXF4hnbEgXb

claude added 2 commits April 20, 2026 03:41
Rename every source file under src/ from .js to .ts and wire up a
TypeScript toolchain. This is a "loose" conversion: each file has
`// @ts-nocheck` at the top so the existing dynamic-JavaScript patterns
(untyped class fields, implicit any, etc.) keep working unchanged. Types
can be added incrementally from here.

- Rename src/**/*.js → *.ts and update imports to use .ts extensions
  (required by Node's --experimental-strip-types resolver).
- Update tsconfig.json: target es2022, module/moduleResolution nodenext,
  allowImportingTsExtensions, noEmit, loose strictness.
- Switch webpack from ./src/index.js to ./src/index.ts and use ts-loader
  with transpileOnly. Drop eslint-webpack-plugin (was only checking .js).
- Tests stay as .js but import .ts sources directly; `npm test` now runs
  `node --experimental-strip-types --test ...`.
- Delete the manually maintained .d.ts files (src/*.d.ts, index.d.ts) and
  the typedefs.spec.js test that verified them — TypeScript now enforces
  the contract directly.
- Update bench.js, CLAUDE.md, README.md, and package.json (description,
  exports, files, scripts) to reflect the TypeScript layout.

All 577 tests pass; `npm run build` produces dist/jsnes.js and
dist/jsnes.min.js as before.
Remove `@ts-nocheck` from the exported classes (NES, Controller, Browser,
GameGenie) and add real type annotations to the surface that consumers
see. The internal emulator modules (CPU, PPU, PAPU, mappers, browser
helpers) still have `@ts-nocheck` — references to them from the public
classes are typed as `any` so the implementation keeps working unchanged.

Public types exported from `src/index.ts`:
- `NESOptions`, `EmulatorData`, `ControllerId`, `RomData`
- `ButtonKey`, `ControllerState`
- `BrowserOptions`
- `GameGeniePatch`

The class fields, method parameters, and return types on the exported
classes themselves are also annotated so consumers get IntelliSense on
things like `nes.loadROM(...)`, `controller.buttonDown(...)`, etc.

All 577 tests still pass and the webpack build is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants