typescriptvisual-studio-codetsconfig

Libraries show up in Intellisense even when not included in `typeRoots` or ``types`


I'm building a Typescript declaration file for an external dependency, and am struggling to get my tsconfig.json file to only result in the specified types appearing in Intellisense in VSCode.

I am able to get my library's types to show up successfully, but I am not able to prevent other libraries from showing up.

For example, when I add the text filter into a new .ts file, the VSCode automplete options include filter from the Lodash library, despite me not including Lodash in my tsconfig.

I'm guessing this has something to do with either how I've set up my tsconfig.json, or with some limitation of Typescript "project references".

Here's my file structure:

  • ./tsconfig.json (the root config)
  • ./gml/tsonfig.json (the library I'm working on)
  • ./gml/typings/ (where my library .d.ts files live)
  • ./gml/test.ts (the file where I'm testing Intellisense for types)
  • ./src/ (a related project for which I want separately-managed types, via project references)
  • ./node_modules/ (root node_modules, which does include Lodash and other libraries used by the project in ./src/)

And my configs:

// Root tsconfig
{
  "include": [],
  "exclude": ["node_modules"],
  "typeAcquisition": { "enable": false },
  "compilerOptions": {
    "baseUrl": ".",
    "typeRoots": [],
    "types": []
  },
  "references": [
    {
      "path": "./src/"
    },
    {
      "path": "./gml/"
    }
  ]
}
// ./gml/tsonfig.json
{
  "include": ["./"],
  "exclude": ["node_modules"],
  "typeAcquisition": { "enable": false },
  "compilerOptions": {
    "composite": true,
    "allowJs": true,
    "noEmit": true,
    "lib": ["es2015"],
    "typeRoots": ["./typings"],
    "target": "es2020",
    "module": "none",
    "skipLibCheck": true,
    "strict": true,
    "baseUrl": "."
  }
}

I excepted any of typeAcquisition, typeRoots, and types to successfully allowlist only my library when specified, but no matter what I plug into all of those I still end up with the stuff in my root node_modules/@types being available in Intellisense within ./gml.

Does anyone know how to restrict the types in a project like this? Is not not possible with project references?


Solution

  • Reason

    The reason VS Code's Typescript language server sources a package unexpectedly is most likely that some source file(s) in your project import from a package that (transitively) depends on the package you get Intellisense for.

    Note that it is enough for one file to have such an import and Intellisense for (transitive) dependencies of the imported package will become available in all other source files as well.

    Example

    For example, in the following source file Typescript knows about setImmediate because of the (unused and invalid) import from @types/http-proxy because @types/http-proxy has a dependency on @types/node:

    import { x } from '@types/http-proxy'
    
    setImmediate(() => {})
    

    If you remove or comment out that import, Typescript will show a ts(2304) error: Cannot find name 'setImmediate'.

    There is a suggestion to change @types/*'s dependency on @types/node to become a devDependency since 2021: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/55519

    The example above uses the following tsconfig.json:

    {
        "compilerOptions": {
            "types": [],
            "typeRoots": []
        }
    }
    

    Debugging

    To list the files that Typescript sources for compilation and type checking you can execute this:

    tsc --listFiles --noEmit
    

    Play with imports to see which imports lead to which files being included. It could be helpful to set Typescript's compiler option skipLibCheck to true to only list the files and, yeah, skip checking anything inside the libraries.

    Note that the compiler option

    • module influences how imports are resolved
    • preserveSymlinks influences which files are sourced by Typescript especially if using pnpm as the package manager