4

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?

2
  • Can u please explain what do u mean by "....the globals are not being seen by typescript, ..." Commented Sep 22, 2022 at 1:42
  • For example when you install jest types npm i @types/jest typescript now can see jest globals like describe or it and you can now use them without typescript complaining they do not exists and without you explicitly importing them like import { describe } from 'jest'. Commented Sep 22, 2022 at 4:31

1 Answer 1

2

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" />
Sign up to request clarification or add additional context in comments.

2 Comments

I'm afraid that's going to be the case, I did some quick tests on how much it takes to scan global.ts.d named files inside a big node_modules project and it is not that bad, still in the scale of milliseconds, that will be a good PR/Proposal to make in the Typescript repo, in the mean time I think just referencing the globals is the best alternative so far.
I think this is intentional behavior and a PR wouldn't be considered. Updated answer to try make better argument for this behavior in lieu of anything in the official docs about it. Also people will probably complain about a few milliseconds ;).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.