type-only import
The new type-only import syntax supports most variations of import statement but not this one:
import type 'mod'
It may seem stupid because no type is actually imported?! But it's in fact useful if mod contains some global declarations that you need.
Global declarations are currently only imported from: typeroots (@types/* by default) or types configs; and referenced modules.
~This syntax is even more useful because it can't be emulated today. If you do import 'mod' then typing works _but_ TS assumes you import the module for side-effects and will _not_ erase it.~(EDIT: see triple-slash comment)
I encountered this today.
One package I use provides some dependency injection and basically defines the following module augmentation:
inject(x: 'myType'): MyType
which is a strongly typed overload of
inject<T = unknown>(x: string): T.
Inject itself comes from another library so code that wants to use this import needs to do this:
import { inject } from 'other-lib';
import type 'my-lib';
let my = inject('myType'); // correctly typed as MyType
Current work-arounds include:
import { MyType } from 'my-lib' but if you don't use it in code it'll be a warning;import 'my-lib' but it won't be erased;typeroots or types and do nothing (might be better in some cases).~ (EDIT: not really working, see my comment below for an alternative solution.)/// <reference types="mod" />, which works but I think most people have forgotten about? (I have 馃槣)My suggestion meets these guidelines:
You can use Triple鈥慡lash Directives to achieve this:
/// <reference types="mod"/>
My feeling is that a /// <reference ... /> directive should be the preferred way since we don't want to have multiple ways to do the same thing, but I understand that it's less obvious.
@DanielRosenwasser is it preferred? I thought it was mostly a thing of the past and import types were how it's done now.
I'm gonna edit the OP to add this alternative though.
I'll add that it's surprisingly difficult (impossible?) to add one package that is not in @types to the list of automatically loaded types.
If it's a package sitting under node_modules:
typeroots lest you add all of node_modules (because roots must contain directories for each package).types but since this option disables typeroots you must declare every other types to automatically include, i.e. everything that you have in @types 鈽癸笍None of those seemed acceptable, so the only workaround I could find is to add a global.d.ts file in my project containing this:
// global.d.ts
// Auto global types inclusions, can't be done in tsconfig.json:
/// <references types='mod' />
Because it's inside my project, it'll be picked up.
you can put it in
typesbut since this option disablestyperoots
Woah, is that actually as intended @RyanCavanaugh?
Yah, it is. We use it heavily, ourselves. Specifying types: ['node'] prevents you from loading other garbage (eg, from your build tools dependents) from the modules folder automatically.
I聽personally prefer聽pnpm, which聽uses symbolic聽links to聽ensure聽that your聽package can聽only聽access what鈥檚聽declared in聽package.json.
This makes using "types":聽["node"] redundant.
It's a breaking change, but it may be more intuitive to unlink the two settings (i.e. make them additive).
@weswigham scenario would be
{
"typesroot": [],
"types": ["node"]
}
@ExE-Boss even with pnpm, your @types deps for, say, your gulp build script will be installed to the same folder as the dev dependencies for your main project (assuming you still use a single package.json structure). It helps, but it doesn't fix all scenarios.
try
import type { } from 'my-lib'
Most helpful comment
You can use Triple鈥慡lash Directives to achieve this: