Skip to content

useImportType

Diagnostic Category: lint/style/useImportType

Since: v1.5.0

Sources:

Promotes the use of import type for types.

TypeScript allows specifying a type qualifier on an import to indicate that the import doesn’t exist at runtime. This allows transpilers to safely drop imports of types without looking for their definition. This also ensures that some modules are not loaded at runtime.

The rule ensures that all imports used only as a type use a type-only import. It also groups inline type imports into a grouped import type.

If you use the TypeScript Compiler (TSC) to compile your code into JavaScript, then you can disable this rule, as TSC can remove imports only used as types. However, for consistency and compatibility with other transpilers, you may want to enable this rule. In that case we recommend to enable TSC’s verbatimModuleSyntax. This configuration ensures that TSC preserves imports not marked with the type qualifier.

You may also want to enable the editor setting typescript.preferences.preferTypeOnlyAutoImports from the TypeScript LSP. This setting is available in Visual Studio Code. It ensures the type is used when the editor automatically imports a type.

Caveat with TypeScript experimental decorators

Section titled Caveat with TypeScript experimental decorators

Some frameworks like Angular and NestJS rely on experimental TypeScript decorators which allow code to be generated based on type annotations. This is mainly used for dependency injection.

Since Biome doesn’t know how a decorator is implemented, it is unable to detect that an import used as a type is also used as a value in the code generated by a decorator. This leads Biome to suggest importing some imports as type, which are actually used as value at runtime.

We haven’t found a way to support this pattern yet. We recommend disabling this rule when using such decorators.

This rule respects the jsxRuntime setting and will make an exception for React globals if it is set to "reactClassic".

import { A } from "./mod.js";
type TypeOfA = typeof A;
let a: A;
code-block.ts:1:1 lint/style/useImportType  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

All these imports are only used as types.

> 1 │ import { A } from “./mod.js”;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 │ type TypeOfA = typeof A;
3 │ let a: A;

Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.

Safe fix: Use import type.

1 │ import·type·{·A·}·from·“./mod.js”;
+++++
import { type A, type B } from "./mod.js";
code-block.ts:1:1 lint/style/useImportType  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

All these imports are only used as types.

> 1 │ import { type A, type B } from “./mod.js”;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 │

Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.

Safe fix: Use import type.

1 - import·{·type·A,·type·B·}·from·./mod.js;
1+ import·type·{·A,·B·}·from·./mod.js;
2 2

import { type A, B } from "./mod.js";
let c: A;
let d: typeof B;
code-block.ts:1:1 lint/style/useImportType  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

All these imports are only used as types.

> 1 │ import { type A, B } from “./mod.js”;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 │ let c: A;
3 │ let d: typeof B;

Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.

Safe fix: Use import type.

1 - import·{·type·A,·B·}·from·./mod.js;
1+ import·type·{·A,·B·}·from·./mod.js;
2 2 let c: A;
3 3 let d: typeof B;

import type { A } from "./mod.js";
let a: A;
import { B } from "./mod.js";
let a: B = new B();
import { type A, B } from "./mod.js";
let c: A;
let d = new B();

The rule ignores unused imports and imports with import attributes.

import { A } from "./mod.js";
import { B } from "./mod.js" with {};
export type { B };