Migrating a Tauri app to TypeScript 7 and Oxlint
How I replaced ESLint and typescript-eslint with Oxlint to unlock the native TypeScript 7 compiler in a Vite + Tauri repo.
I migrated a Tauri + React repo from TypeScript 6.0.3 to TypeScript 7.0.2 (the native Go compiler) and replaced the entire ESLint stack with Oxlint. The migration was one PR; the blocker was the ESLint toolchain rather than the compiler itself.
Note
Tested with TypeScript 7.0.2, Oxlint 1.82.0, and Tauri 2.11.4 on 2026-09-12.
The Problem
TypeScript 7 is the native Go port of the compiler, shipping as typescript@7.x on npm with per-platform binaries. I wanted it in this repo for its speed, but typescript-eslint pins its peer dependency to typescript >=4.8.4 <6.1.0, and that range is semantic, not conservative.
I verified why. The typescript@7 npm package’s Node entry point is a lib/version.cjs stub that exports exactly two keys. The JS Compiler API that typescript-eslint’s type-aware rules are built on is gone from the package. No amount of peer-range wrangling fixes that; the rules have no engine to run on.
So the question became: what replaces recommendedTypeChecked? The answer is Oxlint’s type-aware mode, which runs tsgolint (a driver around the same native TS7 compiler) to power type-aware rules and even surface tsc diagnostics as lint errors.
What Changed
Before touching dependencies, I verified the native compiler handles the repo’s exact tsconfig surface. I built a scratch project mirroring it: tsc -b with project references, composite, tsBuildInfoFile incremental builds, noUncheckedIndexedAccess, exactOptionalPropertyTypes, moduleResolution: "Bundler", and allowImportingTsExtensions. All of it works on 7.0.2. Stale .tsbuildinfo files needed deleting once (the format changed); the typecheck and build:web scripts stayed byte-for-byte identical.
For the lint migration I used the official migration tool:
pnpm dlx @oxlint/migrate eslint.config.js --type-aware --details
Per the migration docs, this converts a flat ESLint config into .oxlintrc.json. The parity audit came out as:
- 121 rules migrated, including all 23 type-aware rules from
recommendedTypeChecked(no-floating-promises,await-thenable, and friends) react-hooksandreact-refreshrules map to Oxlint’sreact/plugin (react/exhaustive-deps,react/only-export-components)- 6 rules dropped, each with a stated reason:
no-undefandno-useless-assignmentare nursery-grade in Oxlint (andtsgocovers whatno-undefcaught),no-dupe-argsandno-octalare superseded by ESM strict mode, andreact-hooks/config/react-hooks/gatingare React Compiler gating options this config never used
The dependency diff: out went eslint, @eslint/js, typescript-eslint, eslint-plugin-react-hooks, eslint-plugin-react-refresh, and globals; in came oxlint 1.82.0 and oxlint-tsgolint 7.0.2001. The lockfile shrank by 681 lines net.
Type-aware linting and tsc diagnostics are enabled from the config:
// .oxlintrc.json
{
"options": {
"typeAware": true,
"typeCheck": true
}
}
With typeCheck: true, pnpm lint reports compiler diagnostics inline: a deliberate export const canary: number = "not a number" produced typescript(TS2322) with a codespan from Oxlint itself, no separate tsc invocation.
The editor side (nvim, not VS Code): nvim-lspconfig’s tsc server detects TypeScript ≥7 in node_modules/.bin and runs tsc --lsp --stdio. The stable 7.0.2 binary accepts --lsp even though the flag isn’t in --help output. ts_ls, typescript-tools.nvim, and vtsls are all tsserver-based and don’t apply anymore. TS7 ships no tsserver, just the tsc binary and lib .d.ts files.
For Tauri specifically: nothing needed to change. tauri.conf.json shells out to pnpm build:web (tsc -b && vite build), frontendDist points at Vite output, and the crate has no tauri-specta TypeScript codegen. TS7 never emits here anyway; the repo has been noEmit + Vite since the scaffold.
Results
Measured on this repo (16 lintable files), before → after:
- Lint:
eslint .1.8s →oxlint~0.2s (type-aware, including tsc diagnostics) - Typecheck:
tsc -b0.77s → ~0.3s warm on the native compiler - Lockfile: −681 lines net
- CI and Tauri build hooks: zero command changes
mise run verify passes every gate: format, Oxlint, tsgo typecheck, Vitest, node --test, the tsc -b && vite build production build, and the Rust side.
What I’d Do Differently
I spent a debugging cycle concluding that Oxlint silently ignored options.typeCheck from config while honoring it as a CLI flag. That was wrong. Re-running @oxlint/migrate --type-aware after my manual config edit had produced a duplicate "options" key in .oxlintrc.json. Last key wins in JSON parsing, so my typeCheck: true was clobbered by the regenerated { "typeAware": true } block. Prettier happily formats duplicate-key JSON without complaint. Next time I’ll validate the generated config for duplicate keys before blaming the tool.
References
- TypeScript’s native Go port announcement: the TS7 transition and the JS API removal
- Oxlint: the Rust linter this migrated to
- Oxlint’s migrate-from-ESLint guide: the
@oxlint/migratetool used here - Oxlint type-aware linting:
--type-aware --type-checksemantics - nvim-lspconfig: the
tscserver config that speakstsc --lsp --stdio - typescript-eslint: the tooling this replaced, and the
<6.1.0peer range that forced the decision
This post was written with AI assistance.