Skip to content

Type check with the TypeScript 7 native compiler - #338

Open
pysnooLab wants to merge 3 commits into
mainfrom
feat/typescript-7
Open

Type check with the TypeScript 7 native compiler#338
pysnooLab wants to merge 3 commits into
mainfrom
feat/typescript-7

Conversation

@pysnooLab

@pysnooLab pysnooLab commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Problem

TypeScript 7 (GA on 2026-07-08) is the Go compiler and is around 10x faster, but it cannot simply replace typescript@5.8: it no longer ships the JS API that typescript-eslint needs. Upstream closed the TypeScript 7 support request as not planned until that API lands in 7.1, so a plain bump breaks ESLint on every .ts/.tsx.

The codebase was not TS 7 ready either: baseUrl has been removed from the compiler options, and getList/getOne were redeclared non generic in the Supabase data provider while several call sites pass a type argument (getOne<Sale>). TS 5.8 accepted that, TS 7 rejects it with TS2558.

Solution

The side by side setup documented in the TypeScript 7.0 announcement:

  • tsc comes from typescript@7 through the @typescript/native alias
  • the typescript entry resolves to @typescript/typescript6, so ESLint keeps a supported peer
  • typescript-eslint floor raised to ^8.58.0, the first release whose peer range widens to typescript <6.1.0. Below that, npm ci refuses the resolution outright.

The two binaries do not collide (tsc for 7, tsc6 for 6), so no script and no CI job changed. Removing the alias is all it takes once typescript-eslint supports 7.1.

Plus the compatibility fixes, all of which stay valid on TS 5.8:

  • baseUrl dropped from both tsconfigs (paths now resolve relative to the tsconfig file, and tsconfig-paths 4.2 used by the Storybook docgen reports the same absoluteBaseUrl without it)
  • getList/getOne made generic in the Supabase and FakeRest providers, which fixes the call sites at the root instead of stripping their type arguments
  • scrollMargin added to the IntersectionObserver stub in the notes test, now required by the lib.dom shipped with TS 7

Measured here, 5 runs each: type checking drops from a 4.66s median to 1.10s (4.2x). The build is unchanged, vite build does not go through tsc.

Two known limits, both dormant:

  • tsconfig.node.json (the vite.config.ts project) fails under TS 7 because the program pulls in node_modules/@swc/html/index.ts, a raw .ts shipped by a third party, incompatible with verbatimModuleSyntax. No script or CI job targets that project today.
  • The editor needs the TypeScriptTeam.native-preview extension (VS Code >= 1.126) to get the native language server, it is not built into VS Code yet as of 1.131.

How to test

npm ci
npx tsc --version   # Version 7.0.2
npm run typecheck   # clean
npm run lint        # clean, ESLint still runs every rule
npm run test        # 405 passed on app + claude, 108 on functions

TypeScript 7 removes the baseUrl option, so paths now resolve relative to
the tsconfig file. tsconfig-paths 4.2, used by the Storybook docgen,
reports the same absoluteBaseUrl without it, so the tooling is unaffected.

getList and getOne were redeclared non generic in the Supabase data
provider, while several call sites pass a type argument such as
getOne<Sale>. TypeScript 5.8 accepted it, TypeScript 7 rejects it with
TS2558. Making both methods generic fixes the call sites at the root
rather than stripping their type arguments.

The IntersectionObserver stub in the notes test gains scrollMargin, which
the lib.dom shipped with TypeScript 7 declares as required.

Both compilers type check clean after this change, so this stays valid on
TypeScript 5.8.
typescript@7 is the Go compiler and no longer ships the JS API that
typescript-eslint needs. Upstream closed the TypeScript 7 support request
as not planned until that API lands in 7.1, and points at the side by side
setup documented in the 7.0 announcement.

So tsc now comes from typescript@7 through the @typescript/native alias,
while the typescript entry resolves to @typescript/typescript6 so eslint
keeps a supported peer. The two binaries do not collide, tsc for 7 and
tsc6 for 6, so no script needed a change.

Measured on this project, five runs each: type checking drops from a
4.66s median to 1.10s.
@pysnooLab pysnooLab added the RFR label Aug 4, 2026
The lockfile pinned typescript-eslint 8.41.0, whose peer range is
typescript >=4.8.4 <6.0.0 and therefore excludes the 6.0.2 compatibility
package. ESLint itself runs fine on that pair, but npm ci refuses the
resolution and the CI could not install at all.

8.58.0 is the first release widening the range to <6.1.0, so it becomes
the floor. npm ci --dry-run now resolves clean.
Comment thread tsconfig.json
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsconfig.node.json no longer compiles under TS 7, so vite.config.ts is untypecheckable.

Comment thread package.json
"test:unit:functions": "vitest --config vitest.config.ts --project functions",
"dev": "vite --force",
"dev:demo": "vite --config vite.demo.config --force",
"build": "tsc && vite build",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsc type-checks nothing (files: []). We need to find another way (like npm run typecheck. But without the npm to let users use their own package manager)

Comment thread package-lock.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still can find typescript6 in the package-lock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants