Although commonly used interchangeably, they are not actually equivalent. There exist two key differences between them that hold significance based on the context.
import type
transforms a file into a module.
The TypeScript compiler distinguishes whether the top-level scope of a TypeScript file is module-scoped or globally scoped by detecting the presence of any import
or export
declarations. In this regard, import type
functions as an import declaration, meaning that if it stands alone as the only import/export statement in the file, replacing it with a type alias would shift the classification of the file from a module to a script. This distinction becomes relevant when dealing with files (typically .d.ts files) that require global scope but necessitate referencing types from a module - where you are left with no choice but to utilize type Foo = import(...)
.
import type
can encompass both value and namespace connotations.
By creating a type alias using type Foo = import('./').Bar
, Foo
exclusively represents a type, even if Bar
possesses both type and value significances (e.g., class Bar {}
). The declaration completely disregards the value aspect of Bar
. Essentially, import type
directly points to the complete symbol for Bar
along with all its implications; it merely establishes a syntactic validation to prevent its utilization in a context that would be emitted to JS (considering that the import statement will be erased in JavaScript). This distinction bears relevance in various scenarios, best elucidated through an example:
import type { EventEmitter as EE1 } from "events";
type EE2 = import("events").EventEmitter;
// Valid since 'declare' signifies that 'Foo1' is not utilized in an emitting position.
declare class Derived1 extends EE1 {}
declare class Derived2 extends EE2 {}
// ^^^
// Error: 'EE2' solely refers to a type but is being employed as a value here.
type EventEmitterCtor1 = typeof EE1; // Valid
type EventEmitterCtor2 = typeof EE2;
// ^^^
// Error: 'EE2' just pertains to a type but is treated as a value here.
const x = EE1;
// ^^^
// Error: 'EE1' cannot serve as a value due to being imported via 'import type'
const y = EE2;
// ^^^
// 'EE2' uniquely denotes a type but is perceived as a value here.
(Access Playground link)