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" />