Typescript: tsconfig with paths and include causes vscode to drop intellisense on paths

Created on 24 Sep 2018  路  7Comments  路  Source: microsoft/TypeScript

_From @ca0v on September 21, 2018 16:8_

  • VSCode Version: 1.27.2
  • OS Version: win10

Steps to Reproduce:
this gist show the steps to reproduce but it comes down to this tsconfig.json file:

{
    "compilerOptions": {
        "baseUrl": "./",
        "paths": {
            "@app/*": ["./app/*"]
        }
    },
    "xinclude": ["app/**/*.ts"]
}

If you remove the "x" in "xinclude" intellisense immediately breaks in vscode:

import { MyApp } from "@app/myapp";

_Copied from original issue: Microsoft/vscode#59116_

Completion Lists TSServer Working as Intended

Most helpful comment

I just spent a little time reproducing these examples. Everything shown here is expected behavior. I think I can explain what鈥檚 happening, why @ca0v鈥檚 workaround works, and why @rhyek鈥檚 workaround does not work. From this, I think it should be clear how to fix your config. TL;DR: @mjbvz is correct in his earlier comment.

What鈥檚 happening

There are two facts you need to be aware of to understand what鈥檚 happening here. The first is probably obvious; the second, I would wager, is the root of the confusion:

  1. For path mapping to work in a given file, that file needs to accounted for by some tsconfig.json that defines the path mapping.
  2. The files accounted for by a tsconfig.json file are determined by its files, include, and exclude settings. If you don鈥檛 have any of them, the default is "include": ["**/*"]. If you _do_ provide an include yourself, that _overrides_ the default; it doesn鈥檛 _add_ to the default.

So, in the example of the original repro, when you set "include": ["app/**/*.ts"], _only_ files under app/ (and anything those files import) are part of your program. Files under test/ are orphaned (unless imported by files in app/), so when you open them in VS Code, TS Server infers a phantom project with default settings for them. Those default settings, of course, don鈥檛 contain your custom path mapping.

Why @ca0v鈥檚 workaround works

The workaround shown in this comment implies there is another file called tsconfig.json with default files/include/exclude settings, which means that it represents a project by itself that accounts for all files. This also implies the tsconfig content shown in the comment must be a file named something other than tsconfig.json鈥攍et鈥檚 call it tsconfig.custom.json for the sake of example. The result is that VS Code will totally ignore that file. But, if you run tsc -b tsconfig.custom.json, it won鈥檛 compile files in test/ (unless something in app/ imports them).

Why @rhyek鈥檚 workaround doesn鈥檛 work

@rhyek鈥檚 base tsconfig file is named tsconfig.base.json, which means VS Code won鈥檛 see it as a project in its own right; it will only be used where another file actually named tsconfig.json extends it (in this case, /projects/apps/project-a/tsconfig.json). But /projects/apps/project-a/tsconfig.json has "include": ["./types/**/*"], which means it _only_ includes files in ./types, orphaning /projects/apps/project-a/test.ts!

The general solution

Adding include to your tsconfig doesn鈥檛 add _more_ files within your project folder; it filters files down from the highly-inclusive default. The irony in all these examples is that the include was never needed, since everything that was being included would have been covered by the default. It鈥檚 quite possible these examples were distilled into simpler cases, and your real projects _did_ need to use include in one way or another, but the takeaway is to make sure your include covers _everything_ that you want the compiler to know about. (My advice is always to go without any files/include/exclude until you need it.)

The specific solution, maybe

Since both of these examples mention test files, it鈥檚 worth noting that you might decide that you don鈥檛 want your test files included as part of your main program, but you still want to be able to use path mapping in them. The easiest way for this to work properly from both the command line and from VS Code is to put your tests and sources in separate folders, each folder with its own tsconfig.json (it鈥檚 important for TS Server鈥檚 sake that it鈥檚 named exactly tsconfig.json), each of which extends a common ../tsconfig.base.json that defines the path mapping.

(If you want to mix your tests and sources in the same folder, but have your tests excluded from the main project, you can get this to work with tsc fairly easily, but TS Server / VS Code will have trouble understanding your intent because it looks for files named exactly tsconfig.json, and obviously you can鈥檛 have two files by the same name in the same folder. There may be some highly creative workaround to doing this, but I鈥檓 not prepared to make any recommendations here. I think @OliverJAsh may have an issue tracking this.)

All 7 comments

_From @ca0v on September 21, 2018 16:14_

There is a workaround to this. Keep your primary tsconfig.json file free if "files", "include" and "exclude" elements and introduce a derived tsconfig file:

{
    "extends": "./tsconfig",
    "compilerOptions": {
        "outFile": "./built/app.max.js"
    },
    "include": ["./app/**/*.ts"]
}

I believe that this is by design since folders in the test directory are not included in the tsconfig.json project that defines the path mapping. Your workaround also seems reasonable.

Someone on the TS team can verify this however

Any new info on this? The workaround isn't working for me using the latest TS and VSC versions.

I have something like this:

/project
  tsconfig.base.json
  /shared
  /apps
    /project-a
      types/
      test.ts
      tsconfig.json

tsconfig.base.json:

{
  "compilerOptions: {
    "baseUrl: "./",
    "paths": {
      "@shared/*": ["shared/*"]
    }
}

project-a/tsconfig.json

{
  "extends": "../../tsconfig.base.json",
  "include": ["./types/**/*"]
}

test.ts

import Roles from '@shared/enums/roles'; // error
import lib from 'bitcore-lib'; // no error; type definitions are in ./types/...

If I remove the "include" in project-a/tsconfig.json, the errors are switched!

Same problem with latest version of vscode.

For me this issue was related to https://github.com/Microsoft/TypeScript-Sublime-Plugin/issues/605. Excluding the .spec.ts files caused intellisense to break. For now I removed the include/exclude and allow typescript to build the .spec.ts files. Another option would be to restructure and put test files in a sibling directory to the src and provide an additional tsconfig.json. It would be nice to exclude test files from build and have test file with intellisense.

I just spent a little time reproducing these examples. Everything shown here is expected behavior. I think I can explain what鈥檚 happening, why @ca0v鈥檚 workaround works, and why @rhyek鈥檚 workaround does not work. From this, I think it should be clear how to fix your config. TL;DR: @mjbvz is correct in his earlier comment.

What鈥檚 happening

There are two facts you need to be aware of to understand what鈥檚 happening here. The first is probably obvious; the second, I would wager, is the root of the confusion:

  1. For path mapping to work in a given file, that file needs to accounted for by some tsconfig.json that defines the path mapping.
  2. The files accounted for by a tsconfig.json file are determined by its files, include, and exclude settings. If you don鈥檛 have any of them, the default is "include": ["**/*"]. If you _do_ provide an include yourself, that _overrides_ the default; it doesn鈥檛 _add_ to the default.

So, in the example of the original repro, when you set "include": ["app/**/*.ts"], _only_ files under app/ (and anything those files import) are part of your program. Files under test/ are orphaned (unless imported by files in app/), so when you open them in VS Code, TS Server infers a phantom project with default settings for them. Those default settings, of course, don鈥檛 contain your custom path mapping.

Why @ca0v鈥檚 workaround works

The workaround shown in this comment implies there is another file called tsconfig.json with default files/include/exclude settings, which means that it represents a project by itself that accounts for all files. This also implies the tsconfig content shown in the comment must be a file named something other than tsconfig.json鈥攍et鈥檚 call it tsconfig.custom.json for the sake of example. The result is that VS Code will totally ignore that file. But, if you run tsc -b tsconfig.custom.json, it won鈥檛 compile files in test/ (unless something in app/ imports them).

Why @rhyek鈥檚 workaround doesn鈥檛 work

@rhyek鈥檚 base tsconfig file is named tsconfig.base.json, which means VS Code won鈥檛 see it as a project in its own right; it will only be used where another file actually named tsconfig.json extends it (in this case, /projects/apps/project-a/tsconfig.json). But /projects/apps/project-a/tsconfig.json has "include": ["./types/**/*"], which means it _only_ includes files in ./types, orphaning /projects/apps/project-a/test.ts!

The general solution

Adding include to your tsconfig doesn鈥檛 add _more_ files within your project folder; it filters files down from the highly-inclusive default. The irony in all these examples is that the include was never needed, since everything that was being included would have been covered by the default. It鈥檚 quite possible these examples were distilled into simpler cases, and your real projects _did_ need to use include in one way or another, but the takeaway is to make sure your include covers _everything_ that you want the compiler to know about. (My advice is always to go without any files/include/exclude until you need it.)

The specific solution, maybe

Since both of these examples mention test files, it鈥檚 worth noting that you might decide that you don鈥檛 want your test files included as part of your main program, but you still want to be able to use path mapping in them. The easiest way for this to work properly from both the command line and from VS Code is to put your tests and sources in separate folders, each folder with its own tsconfig.json (it鈥檚 important for TS Server鈥檚 sake that it鈥檚 named exactly tsconfig.json), each of which extends a common ../tsconfig.base.json that defines the path mapping.

(If you want to mix your tests and sources in the same folder, but have your tests excluded from the main project, you can get this to work with tsc fairly easily, but TS Server / VS Code will have trouble understanding your intent because it looks for files named exactly tsconfig.json, and obviously you can鈥檛 have two files by the same name in the same folder. There may be some highly creative workaround to doing this, but I鈥檓 not prepared to make any recommendations here. I think @OliverJAsh may have an issue tracking this.)

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jbondc picture jbondc  路  3Comments

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

weswigham picture weswigham  路  3Comments

seanzer picture seanzer  路  3Comments