ts-node: ts-node fails when tsc runs ok

I have an app with ts-node and ts-babel-node configured (using the register require). When I try to start the app, I get the following error (app specific):

Uncaught exception:  TSError: ⨯ Unable to compile TypeScript
.../verification/spec.ts (21,28): Parameter 'state' implicitly has an 'any' type. (7006)
.../verification/spec.ts (28,28): Parameter 'state' implicitly has an 'any' type. (7006)
    at getOutput (.../node_modules/ts-node/dist/index.js:169:23)
    at Object.compile (.../node_modules/ts-node/dist/index.js:272:19)
    at Module.m._compile (.../node_modules/ts-node/dist/index.js:212:49)
    at Module._extensions..js (module.js:579:10)
    at Object.hook (.../node_modules/ts-babel-node/index.js:52:3)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (.../verification/index.ts:9:13)

But when I run tsc, it gives no errors. Also, in VSCode, I see no error when viewing that file.

I managed to see why this was happening and this block caught my attention (https://github.com/TypeStrong/ts-node/blob/6748fa3780238e60c4c30e14d430d92b5bdc9f10/src/index.ts#L208):

// Add all files into the file hash.
for (const fileName of config.fileNames) {
  if (/\.d\.ts$/.test(fileName)) {
    cache.versions[fileName] = 1
  }
}

If I remove the condition to only add the .d.ts files into the cache, and run the app, I see no errors. I think this condition is not right, as all the files should go to the cache since they are later used for getScriptFileNames in the service host (https://github.com/TypeStrong/ts-node/blob/6748fa3780238e60c4c30e14d430d92b5bdc9f10/src/index.ts#L270).

I’ll try to find a minimal example to repro this since I still don’t understand why is this the case, but just filing this issue with a pointer to that suspicious piece in case you maybe know more about it.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 15
  • Comments: 29 (10 by maintainers)

Most upvoted comments

I’m unable to run ts-node due to a circular reference on types??? I guess? If I comment out the line, it works.

Either way, tsc runs just fine. What does it take to make ts-node run EXACTLY like tsc does? I don’t care about performance, I just want this thing to work like it’s expected to.

@huan it sounds like you want to enable --files mode, which will eagerly load everything matched by includes and files, the same way tsc does. Rather than throwing an error, this will fix the source of the error.

The alternative, throwing the error, involves extra filesystem calls, which imposes a performance hit.

I’ve just noticed it also happens when I import from an index file that exports * from other modules in same directory. Again tsc works fine, ts-node doesn’t

Workaround that worked for me: update file extension from .d.ts to .ts and then import it in your index.ts file

import './types/globals/globals';

I’m also experimenting this issue. If I have *.d.ts files in the src code, ts-node will throw:

/home/juan/.opt/npm/n/lib/node_modules/typescript/lib/typescript.js:86795
        ts.Debug.assert(outputText !== undefined, "Output generation failed");
                 ^
Error: Debug Failure. False expression: Output generation failed

However, tsc works fine

I ran into the same issue today with this block of code:

        throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
              ^
TSError: ⨯ Unable to compile TypeScript

TL;DR run TS-Node with --disableWarnings and the above error should be resolved.

Turns out this is a result of TS-Node stopping when there is a typings error. The default behavior for TSC is to allow the script to compile but show errors. TS-Node will instead take the same exact script and stop execution on it.

A quick example:

const f: string = "HELLO, WORLD!";
console.log(f);
f = 0; // intentional typings error

Let’s do tsc test.ts || node test.js. That gives us the following:

t.ts(3,1): error TS2540: Cannot assign to 'f' because it is a constant or a read-only property.
HELLO, WORLD!

Great, TSC let us know there’s a problem but also compiled the file and it ran fine. Now lets do ts-node test.ts.

        throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
              ^
TSError: ⨯ Unable to compile TypeScript
t.ts (3,1): Cannot assign to 'f' because it is a constant or a read-only property. (2540)
    at getOutput (C:\Users\Scott\AppData\Roaming\npm\node_modules\ts-node\src\index.ts:307:15)
.....

Well there’s that pesky error again. But if we run ts-node --disableWarnings test.ts we get this:

HELLO, WORLD!

Sweet.

The same issue here

node --inspect-brk=29868 --nolazy -r ts-node/register /work/stogram-bot/src/app.ts 
Debugger listening on ws://127.0.0.1:29868/82bae849-546d-4901-9016-6c3ef53d07b1
Debugger attached.
/work/stogram-bot/node_modules/ts-node/src/index.ts:307
source-map-support.js:419
        throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
              ^
TSError: ⨯ Unable to compile TypeScript
source-map-support.js:422
src/routes/index.ts (34,35): Property 'body' does not exist on type 'Request'. (2339)
    at getOutput (/work/stogram-bot/node_modules/ts-node/src/index.ts:307:15)
    at /work/stogram-bot/node_modules/ts-node/src/index.ts:336:16
    at Object.compile (/work/stogram-bot/node_modules/ts-node/src/index.ts:498:11)
    at Module.require.extensions.(anonymous function).m._compile (/work/stogram-bot/node_modules/ts-node/src/index.ts:392:43)
    at Module._extensions..js (module.js:646:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/work/stogram-bot/node_modules/ts-node/src/index.ts:395:12)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Module.require (module.js:579:17)

I don’t think that’s the correct expectation, nor a bug. In Typescript, in VSCode and even in awesome-typescript-loader this is the case for files that augment modules and are not explicitly required. I think it’s not that unexpected given that you specify a directory or explicit files for TS to type check.

In any case, since this is how the other environments work, people rely on this feature, and by not supporting it in ts-node will make those projects to work differently between the editor, client side files, and node files.

Maybe this could be supported with an option to be passed to ts-node? At least it would make sense to have the option to do this.

I’m also going to close this issue since it’s been a bit derailed. If someone has a reproduction of this (an error code of 0 with tsc and node on the output files and non-zero error code of ts-node on the same code), please open a new issue 😄

@leoasis in your repro you might want to use ts-node --no-cache to make sure to run in this issue while experimenting.

As far as behavior goes, I am not sure why this would be bad or incorrect:

if (/\.ts$/.test(fileName)) {
  cache.versions[fileName] = 1;
}

It might end up being slower, but to be honest I don’t see why we should favor performance over correctness… but maybe I fail to understand the issue in its entirety.

Ok I found a quick way to reproduce it. Check this repo I created: https://github.com/leoasis/ts-node-error

There are two scripts to run:

If you run npm run tsc, that will run tsc and you can verify it runs without any errors.

If you run npm run ts-node that will run ts-node start, in which case you can verify there’s an error.

The problem is when there are files that are augmenting other modules, but are not directly required by any of the files in the dependency tree that is started from the starting script file.

This makes me more confident that what I mentioned in the description above is probably the culprit.

Anyway, now there’s a minimal example that fails, hope that helps find the issue. Let me know if you need further info!