Home > Net >  Global Typescript declaration not visible outside node_modules/@types
Global Typescript declaration not visible outside node_modules/@types

Time:09-23

Context

I am developing an npm package using Typescript so types are being shipped alongside the library, basically:

my-package
|- index.js
|- index.d.ts
|- package.json

index.d.ts file contains globals, something like:

declare var thisIsAGlobal: string

The problem

After publishing the package and installed in another project using npm i my-package the globals are not being seen by typescript, unless you explicitly import 'my-package' or /// <reference types="my=package" /> in any file in the project, after that the globals are visible.

Project:

- node_modules
 |- my-library
   |- index.d.ts
- src
 |- index.ts  // thisIsAGlobal global not visible
 |- other_file.ts // thisIsAGlobal global not visible

Discoveries

While trying to reverse engineer Jest types, that mostly export globals, I discovered that the only difference between my globals and Jest globals are the location, Jest globals are in node_modules/@types/jest/index.d.ts while mine are outside node_modules/@types, at the beginning I though there was something to do with package.json or some type configuration but I did the following experiment:

I manually created a single file (with a global in it) inside a folder inside node_modules/@types and the global was visible within my project files.

- node_modules
 |- @types
   |- experiment
     |- index.d.ts  // declare var thisIsAGlobal: number

If I take the experiment file outside the @types directory the global stop being visible within the project files.

- node_modules
 |- @types
 |- experiment
   |- index.d.ts  // declare var thisIsAGlobal: number

You don't even need a package.json file in the @types directory in order for typescript to obtain global types.

Question

Is there something I am missing while publishing a package with global types?

Maybe for types outside @types you need a special configuration?

CodePudding user response:

By default node_modules/@types is always scanned:

By default all visible ”@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible. -- https://www.typescriptlang.org/tsconfig#types

You can see @types being pulled in unconditionally (given default tsconfig.json) with tsc --traceResolution.

It turns out, as you've discovered, node_modules packages are only scanned if you actually import something from the given package. I can't find any justification or discussion for all node_modules packages not being scanned by default, but it seems pretty reasonable not to just scan every package in node_modules for types by default. That's potentially a lot of scanning. Also, any types (global or otherwise) from those packages are only going to be relevant if you actually import something from them (the package can't mutate global state if it's never imported). On the contrary it seems reasonable to scan @types by default so some global types for things like node (@types/node) that you implicitly use but don't import can be gathered. A final argument is that importing all types from node_modules by default will increase the probability of collisions.

The docs do say, if you want to import global declarations from a "global library" and aren't importing anything from it you should use:

/// <reference types="someLib" />
  • Related