Typescript: Add `import type "mod"`

Created on 15 Feb 2020  路  10Comments  路  Source: microsoft/TypeScript

Search Terms

type-only import

Suggestion

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)

Use Cases

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:

  • Importing a type import { MyType } from 'my-lib' but if you don't use it in code it'll be a warning;
  • Import without type import 'my-lib' but it won't be erased;
  • ~Add this lib to typeroots or types and do nothing (might be better in some cases).~ (EDIT: not really working, see my comment below for an alternative solution.)
  • Use /// <reference types="mod" />, which works but I think most people have forgotten about? (I have 馃槣)

Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • [x] This feature would agree with the rest of TypeScript's Design Goals.
Awaiting More Feedback In Discussion Suggestion

Most helpful comment

You can use Triple鈥慡lash Directives to achieve this:

/// <reference types="mod"/>

All 10 comments

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:

  • you can't add it to typeroots lest you add all of node_modules (because roots must contain directories for each package).
  • you can put it in 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 types but since this option disables typeroots

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'
Was this page helpful?
0 / 5 - 0 ratings