Repository navigation
DEV: Type-check with TypeScript 7 - #43406
Merged
Merged
Conversation
davidtaylorhq
force-pushed
the
typescript-7
branch
from
September 11, 2026 17:00
0addf42 to
9a1e85a
Compare
davidtaylorhq
changed the base branch from
main
to
relative-import-extensions
September 11, 2026 17:00
davidtaylorhq
force-pushed
the
relative-import-extensions
branch
2 times, most recently
from
October 15, 2026 10:52
e78e7d2 to
deb1063
Compare
TypeScript 7 checks .gts and .gjs files through a content mapper instead of Glint, and its declaration emit names those files `foo.d.gts.ts` and `foo.d.gjs.ts`. This makes the published types package work with both compilers, so plugins can move over once core does. - `tsconfig-plugin.json` registers `ember-content-mapper` for `.gts` and `.gjs`. TypeScript 6 ignores the `contentMappers` key. - The package `exports` fall back to the `.d.gjs.ts` and `.d.gts.ts` declaration names when there is no plain `.d.ts`. - Generated ambient stubs now export a namespace that a module only exposed as its default export. Without a name for `RSVP.Promise`, declaration emit expanded the type structurally for every plugin file that used a promise from rsvp. TypeScript 6 stops at a depth limit, but tsgo has no such limit and runs until it is out of memory. - `ember-source/types/index.d.ts` is generated so that a `/// <reference types="ember-source/types" />` resolves inside the package.
davidtaylorhq
force-pushed
the
typescript-7
branch
from
October 15, 2026 11:10
9a1e85a to
b6b7056
Compare
TypeScript 7 (tsgo) replaces Glint's `ember-tsc` for type-checking. It type-checks `.gts` and `.gjs` files itself, using `ember-content-mapper` to transform the templates, and its own language server replaces the Glint tsserver plugin in editors. The whole solution now checks in about 10 seconds and 3GB of memory, where the Glint build needed an 8GB Node heap and several minutes. - `typescript-7` is an alias for the 7.1 nightly. `typescript` stays at 6.x because `typescript-eslint` does not accept 7 yet, so the scripts call the 7 binary by path. - Every tsconfig registers the content mapper and adds `*.gjs`/`*.gts` fallbacks to its `paths`, because TypeScript 7 only resolves a mapped file when the specifier has the extension. Relative imports of `.gts` and `.gjs` modules now carry the extension. - The VS Code recommendations gain the TypeScript (Native Preview) extension, which Glint 2 hands `.gts`/`.gjs` files to. `@glint/tsserver-plugin` stays configured for editors still on the built-in TypeScript 6 server, which needs it to resolve `.gts` imports from `.ts` files. TypeScript 7 does not load tsserver plugins, so it costs nothing there. - `ajax` and `debounce` take rest parameters instead of reading `arguments`, and `d-otp` writes its callback types in TypeScript syntax, since TypeScript 7 infers neither the `arguments` object nor Closure-style function types. - `d-close-on-click-outside` declares its signature. Glint dropped the arity error that `d-float-body` gets without it, because the error landed on generated text with no source position. - The discourse-ai sentiment controller annotates a return type that could not be named from the plugin. - ESLint ignores `*.d.gjs.ts` and `*.d.gts.ts`, the declaration names TypeScript 7 emits for mapped files. Plugins and themes keep passing under the published `@discourse/types` until the package is republished with the content mapper configuration and the rsvp stub fix, so this depends on that release.
Bundled plugins and themes now take `@discourse/types` from the pnpm workspace and reference the core project, so `tsc -b` builds core declarations first and checks every plugin against them in the same run. A core type change no longer needs a package release and a version bump before plugins see it, and the language server resolves core imports straight to core source. - Every plugin and theme depends on `discourse` as `workspace:@discourse/types@*` and lists `frontend/discourse` in `references`. - The shared plugin config writes each project's build info next to its own `tsconfig.json`, since all of them used to share one path under `declarations`. - `pnpm install` regenerates the external type stubs through a `prepare` script, so a fresh checkout has them before the first type check. - The publish workflow keeps publishing `@discourse/types` for plugins outside this repository and no longer opens a bump PR. - An integrity spec drives the TypeScript language server from a plugin file and checks that "go to definition" on core `.ts`, `.js`, `.gts` and `.gjs` imports lands in core source.
`typescript` now resolves to the TypeScript 7 nightly, so `tsc` is tsgo across the repository and the scripts no longer need the `typescript-7` alias. TypeScript 6 stays only where a tool uses the TypeScript JavaScript API, which TypeScript 7 does not ship. - ESLint keeps TypeScript 6 through `@discourse/lint-configs`, which depends on it directly. A package extension gives lint-configs its own `@typescript-eslint/parser`. Without it, the parser that `ember-eslint-parser` asks for as a peer resolved `typescript` from the root. - The `typescript` override now only applies to `@glint/tsserver-plugin`, which still runs inside the TypeScript 6 server in editors. The repository-wide override also rewrote peer ranges, which hid that `eslint-plugin-tsdoc` pins an older `@typescript-eslint/utils` that does not accept TypeScript 6. That plugin now uses the same `@typescript-eslint/utils` as the rest of lint-configs. - `discourse-i18n` emits its declarations with `tsc` instead of Glint's `ember-tsc`. - `@discourse/types` has TypeScript 6 as a dev dependency, because `dts-generator.ts` uses the compiler API. - Glint's `ember-tsc` now gets TypeScript 7 as its peer. The content mapper only uses its template transform, which does not load `typescript`.
`dts-generator.ts` now reads declaration files through the TypeScript 7 API, so `@discourse/types` no longer needs TypeScript 6. The generated stubs are byte-for-byte the same as before. - The generator only ever needs to wrap and rewrite `.d.ts` files. A few packages also ship `.ts` sources, but the declarations emitted from them never reached the output, so that path is gone along with its diagnostics handling. - `isDeclaredExternalModule` is gone too, since `generate-external-types.js` never read it. - TypeScript 7 has no JavaScript parser, so the generator starts a tsgo process through `typescript/unstable/sync` and reads each file's syntax tree from it. That API is marked unstable and may change between TypeScript 7 releases.
`typescript` moves to `7.1.0-dev.20260930.4`, `@glint/ember-tsc` to 1.11.6 and `@glint/tsserver-plugin` to 2.7.9. `ember-content-mapper` 0.3.1 and `@glint/template` 1.9.0 are already the latest releases. - This is the newest nightly without microsoft/TypeScript#64656. From `7.1.0-dev.20261001.1` on, declaration emit fails with TS5088 on an inferred type that refers to itself, where earlier versions wrote `any` at the cycle. Seven places in core hit it. - In newer nightlies, the sync API's `createProgram` takes the compiler options as its second argument. `dts-generator.ts` now passes an empty object there, which works with both forms.
The backend job deletes `node_modules` before running RSpec, so the language server spec had no `tsc` to start and failed with `EOFError`. The same check is now a `node:test` file in `@discourse/types`, which runs in the linting workflow next to the type check, where `node_modules` is present. - It opens a plugin file in the TypeScript 7 language server and checks that "go to definition" on core `.ts`, `.js`, `.gts` and `.gjs` imports lands in core source, and that the file has no diagnostics. - When the server exits early, the failure includes the server's stderr. - `pnpm --dir=frontend/discourse-types test` runs it locally.
davidtaylorhq
force-pushed
the
typescript-7
branch
from
October 15, 2026 16:44
46a834d to
e543091
Compare
…ainer `.vscode/extensions.json` recommends TypeScript (Native Preview), but the devcontainer's own extension list did not include it. Editors in the devcontainer stayed on VS Code's built-in TypeScript 6 server instead of TypeScript 7's language server, which Glint 2 hands `.gts` and `.gjs` files to.
The VS Code recommendations, the devcontainer and the types guide named the extension `TypeScript.native-preview`, which does not exist. Its ID is `TypeScriptTeam.native-preview`, and the Marketplace now calls it TypeScript 7, so the guide uses that name.
`block-outlet.gts` passes the outlet info debug component a default block, but its copy of that component's signature declared no blocks. With strict mode on, TypeScript 7 reports this as an implicit `any` at both call sites. Glint's `ember-tsc` drops the error, because it lands on generated code with no source position.
lint-configs 3.8.1 lists `@typescript-eslint/parser` as its own dependency, so ESLint's parser now finds the TypeScript 6 that lint-configs installs, with no help from core. The `packageExtensions` entry that added the parser for it is gone.
The JSDoc typedef described the positional args as `Args.Positional.0` and `[Args.Positional.1]`. TypeScript 7 writes those into the declaration file as properties with no name, which TypeScript 5 and 6 cannot parse. Themes and plugins include every declaration file from `@discourse/types`, so this one file failed their whole type check. A labeled tuple gives the same types and keeps the descriptions in the labels.
lint-configs 3.8.2 lints with TypeScript 5.9, which the `@typescript-eslint/utils` version that `eslint-plugin-tsdoc` pins accepts. The override that moved that plugin onto a newer `@typescript-eslint/utils` is gone.
`ember-tsc` could not find `@glimmer/manager`, so the blocks decorator declared the two functions it uses in an ambient shim. TypeScript 7 resolves the module from the stable types in `ember-source`, so the shim is unused.
The skill described `pnpm lint:types` as `ember-tsc -b`, and its conversion reference named `ember-tsc` as the check that misses runtime module-resolution errors. Both now name `tsc`. The guidance itself is unchanged.
cvx
approved these changes
Oct 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This moves type-checking from Glint's
ember-tscto TypeScript 7. TypeScript 7 checks.gtsand.gjsfiles itself, throughember-content-mapper. A full check of core, plugins and themes takes about 15 seconds and 3GB of memory. The Glint build needed an 8GB Node heap and several minutes.typescriptis now the TypeScript 7 nightly, andpnpm lint:typesrunstsc -b --runExternalCode. ESLint runs on TypeScript 5.9 through lint-configs, and TypeScript 6 stays only for@glint/tsserver-plugin.@discourse/typesfrom the workspace and reference the core project. Onetsc -brun checks core and every plugin, and a core type change no longer needs a package release first.@discourse/typesworks with both TypeScript 6 and 7, so plugins outside this repository can move over when they are ready.7.1.0-dev.20260930.4. Later nightlies fail in seven places in core because of Declaration emit errors (TS5088) on anonymous cyclic types that 6.0 elided toanymicrosoft/TypeScript#64656.For editors, install the TypeScript 7 extension (
TypeScriptTeam.native-preview) and Glint 2 (1.4.0 or newer). Both are in the VS Code recommendations and the devcontainer. Editors on VS Code's built-in TypeScript server keep working through@glint/tsserver-plugin.