Skip to content

(Twoslash) Enhancement: Support TypeScript 7 (native Go port) — tracking + blockers #124

Description

@IEvangelist

Summary

With TypeScript 7 — the native Go port now shipping (typically 8–12× faster type-checking), it would be great for @ec-ts/twoslash, @ec-ts/twoslash-vue, @ec-ts/vfs, and expressive-code-twoslash to eventually support it.

This is a tracking issue, not a bug report. The native typescript@7 package doesn't yet expose the APIs Twoslash relies on, so I've documented the concrete blockers here rather than opening a premature PR. Happy to help implement once the upstream primitives are viable.

Current state

All three entry packages consume the classic TypeScript JS API:

  • @ec-ts/twoslash, @ec-ts/twoslash-vue, and expressive-code-twoslash all do import ts from "typescript" and pass it through as tsModule.
  • The engine (@ec-ts/twoslash/src/core.ts) and the VFS (@ec-ts/vfs) use the in-process LanguageService: getQuickInfoAtPosition, getCompletionsAtPosition, getSemanticDiagnostics / getSyntacticDiagnostics, getEmitOutput, plus ts.sys, ts.optionDeclarations, ts.flattenDiagnosticMessageText, ts.versionMajorMinor, and createLanguageService over a virtual System.

There's already some version-aware handling (e.g. dropping baseUrl for TS ≥ 6 in core.ts), but TS 7 is a much larger shift than a compiler-option tweak.

Blockers with the native typescript@7 package

  1. No classic entrypoint. typescript@7.x exports only ./package.json and ./unstable/* — there is no . / main export, and bin is tsc only (no tsserver). As a result, import ts from "typescript" throws ERR_PACKAGE_PATH_NOT_EXPORTED, so the packages fail to import (before any of their code runs) when a consumer is on TS 7.

  2. Different architecture. The typescript/unstable/sync (and /async) API is an out-of-process client: an API that spawns/sockets a native process via msgpack IPC, exposing Snapshot / Project / Program / Checker / Emitter. It's asynchronous at its core (the sync variant is a SharedArrayBuffer/Atomics channel wrapper) and is explicitly marked unstable.

  3. Missing the primitives Twoslash depends on:

    • Hovers — no getQuickInfoAtPosition equivalent. Checker offers getSymbolAtPosition / getTypeAtPosition / typeToString, so hover output would have to be reconstructed, and wouldn't reproduce the classic displayParts / documentation / tags shape one-to-one.
    • Emit (showEmit) — no LanguageService getEmitOutput; emit is limited to Emitter.printNode (AST → text), not transpile-to-JS of a virtual source file.
    • DiagnosticsProgram.getSemanticDiagnostics / getSyntacticDiagnostics exist, but with a different Diagnostic / position / DocumentIdentifier model than the classic LanguageService output the code currently consumes.
    • VFS model mismatch@ec-ts/vfs's createVirtualTypeScriptEnvironment builds an in-memory LanguageServiceHost over a Map-backed System and calls createLanguageService. The native API has no in-memory System / createLanguageService; it uses a snapshot/document (LSP-style) model in a separate process.

Rough scope (for whenever this is viable)

  • A native-backed environment in @ec-ts/vfs targeting typescript/unstable/sync (snapshot/document model instead of createLanguageService).
  • A hover/quickinfo shim reconstructed from Checker primitives.
  • Diagnostic + position adapters mapping onto the existing twoslash-protocol node shapes.
  • An emit path for showEmit (or documenting it as unsupported under TS 7 initially).
  • Handling the async-native process (sync channel) and the churn of the unstable API surface.

Given the size, this likely wants to wait until the native API stabilizes the LanguageService-style primitives (quickinfo / completions / emit), or ships a compatibility layer.

Interim suggestion (optional, low-risk)

Until then, consumers who happen to be on TS 7 hit a cryptic ERR_PACKAGE_PATH_NOT_EXPORTED. A small guard could improve the experience — e.g. tightening the typescript peer range (the catalog:min entry) to exclude v7, and/or emitting a clearer error when a non-classic tsModule is detected. Happy to open that as a separate, self-contained PR if it'd be welcome.

References

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions