typeImports
Reports imports that do not match the configured type import style.
✅ This rule is included in the ts stylistic presets.
TypeScript’s import type syntax marks imports that exist only for type checking.
Those imports are removed from emitted JavaScript without requiring the transpiler to understand the imported module’s types.
This rule enforces a consistent style for imports whose bindings are only referenced in type positions.
By default it reports regular imports that should use import type.
It can also enforce the opposite style with regular imports instead of import type.
Using a consistent type import style makes each import’s runtime behavior clear. The default preference also helps single-file transpilers remove type-only imports without needing type information from the whole project.
Examples
Section titled “Examples”Type-only named imports
Section titled “Type-only named imports”import { User } from "./types";
type Admin = User & { isAdmin: boolean };import type { User } from "./types";
type Admin = User & { isAdmin: boolean };Mixed type and value imports
Section titled “Mixed type and value imports”import { User, createUser } from "./users";
type Admin = User & { isAdmin: boolean };const user = createUser();import type { User } from "./users";import { createUser } from "./users";
type Admin = User & { isAdmin: boolean };const user = createUser();With the default fixStyle: "separate-type-imports", mixed imports are split into a separate import type declaration.
Default and namespace imports
Section titled “Default and namespace imports”import User from "./types";
type Admin = User & { isAdmin: boolean };import * as Types from "./types";
type Admin = Types.User & { isAdmin: boolean };import type User from "./types";
type Admin = User & { isAdmin: boolean };import type * as Types from "./types";
type Admin = Types.User & { isAdmin: boolean };Type queries
Section titled “Type queries”References inside typeof type queries are safe to convert to import type.
import User from "./types";
type UserConstructor = typeof User;type UserName = typeof User.name;import type User from "./types";
type UserConstructor = typeof User;type UserName = typeof User.name;Type-only exports
Section titled “Type-only exports”Imports that are only re-exported with export type can use import type.
import { User } from "./types";
export type { User };import type { User } from "./types";
export type { User };Regular export { User } and export default User may create runtime exports, so this rule treats them as value usages unless the import is already type-only.
Computed property names in type literals
Section titled “Computed property names in type literals”Computed property names in type-only declarations can reference values for type checking. This rule allows those imports to become type-only when the containing type is erased.
import * as constants from "./constants";
type Values = { [constants.value]: readonly string[];};import type * as constants from "./constants";
type Values = { [constants.value]: readonly string[];};Options
Section titled “Options”Defaults
Section titled “Defaults”{ "fixStyle": "separate-type-imports", "prefer": "type-imports"}prefer
Section titled “prefer”prefer controls whether the rule expects type-only imports or regular imports for bindings used only as types.
It defaults to "type-imports".
"type-imports"reports regular imports that are used only as types."no-type-imports"reportsimport typedeclarations and inlinetypeimport specifiers.
Examples of correct code with { prefer: "type-imports" }, and incorrect code with { prefer: "no-type-imports" }:
import type { User } from "./types";import type UserModel from "./model";
type Admin = User & { model: UserModel };Examples of incorrect code with { prefer: "type-imports" }, and correct code with { prefer: "no-type-imports" }:
import { User } from "./types";import UserModel from "./model";
type Admin = User & { model: UserModel };With { prefer: "no-type-imports" }, inline type specifiers are also reported.
import { type User, createUser } from "./users";
type Admin = User & { isAdmin: boolean };const user = createUser();fixStyle
Section titled “fixStyle”fixStyle controls how auto-fixes are written when prefer is "type-imports".
It defaults to "inline-type-imports".
"inline-type-imports"adds inline type specifiers such asimport { type User } from "./types"when TypeScript syntax allows it."separate-type-imports"adds top-level type-only declarations such asimport type { User } from "./types".
import { User } from "./types";
type Admin = User & { admin: boolean };import type { User } from "./types";
type Admin = User & { admin: boolean };import { type User } from "./types";
type Admin = User & { admin: boolean };Default imports and namespace imports cannot use inline type specifiers.
They are fixed to top-level import type declarations even when fixStyle is "inline-type-imports".
import type User from "./types";import type * as Types from "./types";import() Type Annotations
Section titled “import() Type Annotations”This rule does not report import() type annotations.
Use top-level import type declarations if your project wants to avoid inline import() type references.
Examples of code this rule allows:
type User = import("./types").User;let value: import("./types").User;Decorator Metadata Caveat
Section titled “Decorator Metadata Caveat”When a file contains decorators and the TypeScript compiler options enable both experimentalDecorators and emitDecoratorMetadata, TypeScript can emit runtime metadata for types that appear only in type annotations.
In that configuration, this rule does not report import declarations from decorated files because changing those imports to import type can change emitted decorator metadata.
This caveat only applies to legacy experimental decorators with emitted decorator metadata.
Files using stable decorators without emitDecoratorMetadata are reported normally.
Comparison with verbatimModuleSyntax
Section titled “Comparison with verbatimModuleSyntax”TypeScript’s verbatimModuleSyntax compiler option also distinguishes type-only imports from value imports.
This rule and verbatimModuleSyntax overlap, but they are not identical.
| Situation | This rule | verbatimModuleSyntax |
|---|---|---|
| Unused imports | Ignores them | Can report a compiler error |
| Files with legacy decorator metadata | Ignores decorated files | Uses TypeScript’s emit behavior |
| Feedback location | Lint report with fixes | Compiler error |
Inline imports such as import { type User } from "./types" | Allowed by default | Can emit an empty runtime import in some configurations |
Use this rule when you want lint feedback and auto-fixes for import style.
Use verbatimModuleSyntax when you want the TypeScript compiler to enforce that syntax during builds.
When Not To Use It
Section titled “When Not To Use It”If your project intentionally keeps type-only dependencies in regular imports, configure { prefer: "no-type-imports" } or disable this rule.
If your project already relies on TypeScript’s verbatimModuleSyntax errors for import consistency, you may not need this rule because the compiler will reject many related import forms.
Large existing projects may also prefer to adopt this rule gradually because it can change many import declarations at once.
Related Rules
Section titled “Related Rules”importTypeSideEffectsreports imports such asimport { type A, type B }that may emit empty side-effect imports underverbatimModuleSyntax.
Further Reading
Section titled “Further Reading”- TypeScript: Type-Only Imports and Exports
- TypeScript:
verbatimModuleSyntax - TypeScript 4.5: Type Modifiers on Import Names