Skip to content

ts-node swallows errors for non-executed files (ambient type declarations, .d.ts, referenced but not required .ts) #853

Open

Description

@alexeevg

Say I have a project with files:

index.d.ts:

export declare interface Foo {}

also, let's add some garbage here // invalid Typescript, this should not compile

example.spec.ts:

import {Foo} from '.';

describe('example', () => {
  it('should not compile', () => {
    const foo: Foo = {};
  });
});

Compilation of this project with tsc fails:

> tsc

index.d.ts:3:10 - error TS1005: ';' expected.

3 also, let's add some garbage here // this should not compile
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

index.d.ts:3:61 - error TS1002: Unterminated string literal.

3 also, let's add some garbage here // this should not compile

Found 2 errors.

But running the test with ts-node succeeds:

> mocha --require ts-node/register *.spec.ts

 example
    ✓ should not compile

  1 passing (13ms)

Expected behaviour: the test should fail with the same errors as tsc.

The problem, it seems, is in the way ts-node handles diagnostics only when emitting output for a given file, ignoring the errors in the imported modules: https://github.com/TypeStrong/ts-node/blob/master/src/index.ts#L357

Activity

  1. alexeevg commented on Jul 18, 2019

    @alexeevg
    Author

    Running the example under debugger, I can see that after the service.getEmitOutput(fileName) call the compiler API produces the errors:

    > service.getSemanticDiagnostics(`${process.cwd()}/index.d.ts`)
    result = Array(3)
     0 = Object {file: ,
    start: 33,
    length: 4,
    messageText: "Cannot find name 'also'.",
    category: 1,
    ...}
     1 = Object {file: ,
    start: 33,
    length: 4,
    messageText: "Left side of comma operator is unused and has no side effects.",
    category: 1,
    ...}
     2 = Object {file: ,
    start: 39,
    length: 3,
    messageText: "Cannot find name 'let'.",
    category: 1,
    ...}
    

    But they are ignored, ts-node only reports errors for fileName.

  2. hisabimbola commented on Apr 18, 2020

    @hisabimbola

    Hello @alexeevg

    I am also facing this issue and find it strange that it doesn't report on errors. Were you able to make it work or if you moved to another solution can you share it.

  3. cspotcode commented on Apr 18, 2020

    @cspotcode
    Collaborator

    This sounds like a reasonable enhancement request / bug report for ts-node. The following is probably obvious, but in the interest of precision, I tried to explain exactly how we should do this.

    ts-node needs to roughly match the behavior of node, in terms of throwing errors. When node requires a JavaScript file, if that file has a syntax error, it is thrown. It can be caught just like any other error, but usually this means you want your program to terminate because something is wrong.

    If one JavaScript file requires a bunch of other files -- like when loading a large library -- any syntax errors bubble up the call stack. From the caller's perspective, an error is thrown when anything in the require() tree has an error.

    Once a file is successfully in node's require() cache, it will never be parsed or executed again, so there's no longer a possibility for errors to be thrown.

    We can do exactly the same in TS. If one .ts file causes the TS compiler to load a bunch of other TS files, (.ts, .d.ts, types and/or runtime code) and if any of them have an error (syntactic or semantic) then the require() call should throw.

  4. changed the title [-]ts-node ignores errors in ambient type declarations[/-] [+]ts-node swallows errors for non-executed files (ambient type declarations, .d.ts, referenced but not required .ts)[/+] on Apr 18, 2020
  5. cspotcode commented on Apr 18, 2020

    @cspotcode
    Collaborator

    @alexeevg I renamed the issue title to be a bit more encompassing of the possible swallowed errors.

    It's possible this behavior is intentional. If someone passes ts-node --files then it'll load all .ts files eagerly at the start, and any type errors in the whole codebase will cause it to throw an error immediately when you try to load the first .ts file. Perhaps this was avoided on purpose; I'm not sure.

  6. hisabimbola commented on Apr 18, 2020

    @hisabimbola

    @cspotcode using --files doesn't seem a valid use case for most people. Like highlighted in the readme. Most of the people the application is started by running only the root file ts-node server.ts. And all dependencies are resolved.

    Also to add, I have include in my tsconfig but still no typescript errors

  7. cspotcode commented on Apr 18, 2020

    @cspotcode
    Collaborator

    @hisabimbola I'm not disagreeing, but we need to figure out exactly how to implement this change, which means figuring out every possibility. Even if most people don't use --files, we need to figure out exactly how it will change and how it will behave. This change will make many projects immediately throw type errors before anything loads, whether or not they're using --files.

    --files refers to "include" as well. It means we will use both your "files" and "include" arrays. When you don't specify --files, we set the "files" and "include" arrays to [], then add files to the compiler one at a time as they are require()d.

    --files can greatly improve performance in some cases, because it enables the compiler to typecheck once for the whole program, instead of re-doing the typecheck for each require()d file.

    If someone has the following index.ts:

    if(someflag) {
        const a: import('./other-file').Type = getValue();
    }
    

    other-file.ts is never executed. However, the compiler will still load it. Supposing ./other-file.ts loads ./another.ts, which loads ./something-else.ts. If ./something-else.ts has a type error, then it will be thrown as soon as index.ts is loaded, even though all those other files never executed.

    I still think this change is good, but it's bigger than it might seem at first glance.

  8. cspotcode commented on Apr 20, 2020

    @cspotcode
    Collaborator

    @hisabimbola @alexeevg I made #1018 that should implement the behavior you want, but it's completely untested. I'd appreciate if you can test it, see if it reports the diagnostics you expect, see if it changes performance.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions