Skip to content

repl: add experimental TypeScript support#64077

Open
avivkeller wants to merge 4 commits into
nodejs:mainfrom
avivkeller:repl-ts
Open

repl: add experimental TypeScript support#64077
avivkeller wants to merge 4 commits into
nodejs:mainfrom
avivkeller:repl-ts

Conversation

@avivkeller

Copy link
Copy Markdown
Member

Adds experimental TypeScript support to the REPL, opt-in-able via the --experimental-repl-typescript flag.

@avivkeller avivkeller added repl Issues and PRs related to the REPL subsystem. experimental Issues and PRs related to experimental features. strip-types Issues or PRs related to strip-types support labels Jun 23, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/config
  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Jun 23, 2026
@avivkeller
avivkeller marked this pull request as draft June 23, 2026 00:45
@avivkeller avivkeller added the blocked PRs that are blocked by other issues or PRs. label Jun 23, 2026
Comment thread doc/api/cli.md Outdated
Comment thread test/parallel/test-repl-typescript.js Outdated
Comment thread lib/repl.js Outdated
@Renegade334

Copy link
Copy Markdown
Member

This is going to cause problems with multiline, I suspect.

Concise example:

const regexps = new Set<
  RegExp
>();

If typed as multiline input to REPL, it's going to consider the statement complete after the second newline, as it's a valid JS statement, and evaluate new Set < RegExp, which evaluates to true. I don't know that there's any way around these sorts of parsing conflicts.

@marco-ippolito

Copy link
Copy Markdown
Member

It should be handled exactly like we handle the -e and -p. If it's valid js treat it as such otherwise fallback on TS

@avivkeller
avivkeller marked this pull request as ready for review June 23, 2026 14:27
@avivkeller avivkeller removed the blocked PRs that are blocked by other issues or PRs. label Jun 23, 2026
Comment thread src/node_options.h Outdated
@avivkeller
avivkeller marked this pull request as draft June 28, 2026 18:02
Signed-off-by: Aviv Keller <me@aviv.sh>
@avivkeller
avivkeller marked this pull request as ready for review July 18, 2026 22:41
@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.00000% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (4f844f4) to head (36ba729).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
lib/internal/repl/eval.js 65.21% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64077      +/-   ##
==========================================
- Coverage   90.13%   90.13%   -0.01%     
==========================================
  Files         741      741              
  Lines      241976   242087     +111     
  Branches    45543    45571      +28     
==========================================
+ Hits       218116   218207      +91     
- Misses      15379    15398      +19     
- Partials     8481     8482       +1     
Files with missing lines Coverage Δ
src/node_options.cc 76.72% <100.00%> (+0.02%) ⬆️
src/node_options.h 98.01% <100.00%> (+<0.01%) ⬆️
lib/internal/repl/eval.js 90.55% <65.21%> (-2.62%) ⬇️

... and 33 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@avivkeller

Copy link
Copy Markdown
Member Author

cc @nodejs/typescript

@Renegade334

Copy link
Copy Markdown
Member

It should be handled exactly like we handle the -e and -p. If it's valid js treat it as such otherwise fallback on TS

It's not a blocking concern per se, but I do think that this has the potential to be really quite a UX tripwire. For example, pretty much any use of function template parameters hits this (a<b>(x) is going to be executed as (a < b) > x rather than a(x)), which may match the current behaviour of -e, but I would say is really not what users are going to expect in a REPL environment when explicitly enabling TypeScript mode.

The alternative would be to make TS an explicit on-off repl flag, ie. parse REPL input like it were in a .ts module if the flag is enabled, and unconditionally pass it through Amaro, without speculatively parsing it as JS first.

There is also a subtle difference between REPL and -e, because whereas -e will attempt to evaluate the entire input and fallback if needed, REPL input will be evaluated on a line-by-line basis, multiline REPL input will attempt to evaluate a partial input and potentially tokenize it very differently depending on where the newlines fall (hence the multiline template parameter case above, which -e would handle just fine).

@marco-ippolito

Copy link
Copy Markdown
Member

In the -e you can pass a flag to force the evaluation as module ts or common js ts to disambiguate. In a future where ts support is mixed with js and not behind a flag, js should always be evaluated first

@jasnell

jasnell commented Jul 23, 2026

Copy link
Copy Markdown
Member

I'm not convinced this is the best way to handle this. What might be better is a new REPL command similar to .editor ... something like...

> .typescript
// Entering TypeScript mode (Ctrl+D to finish, Ctrl+C to cancel)
const regexps = new Set<
  RegExp
>();
^D

The otherwise regular behavior of the repl remains untouched.

To cover -e style usage, something like a new -t option can be added:

$ node -pt "const regexps = new Set<RegExp>();"

@targos

targos commented Jul 23, 2026

Copy link
Copy Markdown
Member

There is also a subtle difference between REPL and -e, because whereas -e will attempt to evaluate the entire input and fallback if needed, REPL input will be evaluated on a line-by-line basis, multiline REPL input will attempt to evaluate a partial input and potentially tokenize it very differently depending on where the newlines fall (hence the multiline template parameter case above, which -e would handle just fine).

@Renegade334 I suppose this is mostly a concern for people copy-pasting multiline inputs into the REPL. That may be solvable by supporting paste bracket mode (87af913).

Comment thread lib/internal/repl/eval.js
Comment on lines +128 to +141
if (!valid && experimentalREPLTypeScript) {
try {
const { stripTypeScriptModuleTypes } =
require('internal/modules/typescript');
code = stripTypeScriptModuleTypes(code, file);
} catch (err) {
if (err.code !== 'ERR_INVALID_TYPESCRIPT_SYNTAX' &&
err.code !== 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX') {
throw err;
}
// Let the evaluator report the original JavaScript syntax error. It
// also determines whether incomplete input is recoverable.
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are other subtleties here specific to strip mode and partial/multiline input, even without any TS syntax present.

For example, function foo() is not deemed a valid statement by acorn and fails isValidSyntax(), but throws a recoverable error on evaluation and therefore currently triggers a multiline continuation. However, it's stripped by swc to pure whitespace, so after this change, the line will be discarded completely.

If we stick with the "speculatively type-strip line-by-line on an invalid JS parse" model then it's worth pointing out that previously valid multiline JS could now do weird things.

@avivkeller

Copy link
Copy Markdown
Member Author

In the -e you can pass a flag to force the evaluation as module ts or common js ts to disambiguate. In a future where ts support is mixed with js and not behind a flag, js should always be evaluated first

Would everyone be fine with TypeScript being, as @Renegade334 said, opt-in, not attempt to be JS and fallback?

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

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. experimental Issues and PRs related to experimental features. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. repl Issues and PRs related to the REPL subsystem. strip-types Issues or PRs related to strip-types support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants