| |

TypeScript 75 🔷 Type-Only Imports and Exports

A type-only import brings a type into a file without a runtime’s dependency. The compiler uses it for the checking, and the emitted JavaScript has no trace of it. This matters because TypeScript’s types are erased at the runtime, and the import that is only for the types should not be the emitted. The import type and the export type are the explicit forms, and the verbatimModuleSyntax is the compiler option that enforces them. The type-only’s import is the modern’s, and it is the recommendation’s for the projects that use the bundlers, the transpilers, or the isolatedModules. This chapter covers the type-only’s import, the type-only’s export, the inline’s type modifier, the verbatimModuleSyntax, the isolatedModules, the importsNotUsedAsValues‘s legacy, the patterns, and the pitfalls.

Key point: The import type { User } from './user' imports the User as the type’s only, and the compiler erases it. The import { type User, greet } from './user' is the inline’s, and the User is the type’s while the greet is the value’s. The export type { User } re-exports the type’s only, and the export { type User } is the inline’s. The verbatimModuleSyntax requires the explicit’s type modifier for the type-only’s imports and exports, and it prevents the compiler from the guessing. The isolatedModules requires the file-by-file’s transpilation, and the type-only’s import is the requirement’s. The importsNotUsedAsValues is the legacy’s, and the verbatimModuleSyntax is the modern’s.


Why the type-only’s import exists

The TypeScript’s types are erased at the runtime, and the import that is only for the types is not the runtime’s. The bundler’s and the transpiler’s should not include the import, and the type-only’s import is the way to mark it.

The erased’s types. The interface, the type, the type alias are the erased’s, and the class, the function, the const are the runtime’s. The two are the different, and the different is the type-only’s.

The import‘s ambiguity. The import { User } from './user' is the ambiguous’s, and the ambiguous’s is the type’s or the value’s. The compiler’s guesses, and the guess’s is the problem’s. The import type is the explicit’s, and the explicit’s is the fix’s.

Why the ambiguity matters. The transpiler’s, the bundler’s, the Babel’s, the SWC’s do not know the type’s or the value’s. The isolatedModules‘s is the file-by-file’s, and the file-by-file’s is the transpiler’s. The two are the pair, and the pair is the requirement’s.

Why the type-only’s import matters for the bundler. The bundler’s is the tree-shaking’s, and the tree-shaking’s is the unused’s removal’s. The type-only’s import is the no-runtime’s, and the no-runtime’s is the tree-shaking’s. The two are the pair, and the pair is the optimization’s.

Why the type-only’s import matters for the transpiler. The transpiler’s is the file-by-file’s, and the file-by-file’s is the isolatedModules’s. The transpiler’s cannot know the type’s or the value’s, and the type-only’s is the explicit’s. The two are the pair, and the pair is the correctness’s.

Why the type-only’s import matters for the editor. The editor’s is the language service’s, and the language service’s is the fast’s. The type-only’s import is the separate’s, and the separate’s is the clear’s. The two are the pair, and the pair is the design’s.

Why the type-only’s import matters for the reader. The reader’s is the human’s, and the human’s is the clarity’s. The type-only’s import is the explicit’s, and the explicit’s is the intent’s. The two are the pair, and the pair is the communication’s.

Why the type-only’s import matters for the compiler. The compiler’s is the emit’s, and the emit’s is the erased’s. The type-only’s import is the not-emitted’s, and the not-emitted’s is the output’s. The two are the pair, and the pair is the performance’s.

Why the type-only’s import should be the default. The type-only’s import should be the default, and the default’s is the modern’s. The verbatimModuleSyntax‘s is the enforcement’s, and the enforcement’s is the safety’s. The two are the pair, and the pair is the discipline’s.


The import type

The import type { User } from './user' imports the User as the type’s only, and the compiler erases it.

import type { User } from './user';

function greet(user: User): string {
  return `Hello, ${user.name}`;
}

The import type { User } is the type-only’s, and the type-only’s is the erased’s. The User is the type’s, and the type’s is the function’s parameter’s. The two are the pair, and the pair is the type-only’s.

Why the import type matters. The import type is the explicit’s, and the explicit’s is the intent’s. The compiler erases the import, and the erase’s is the output’s. The two are the pair, and the pair is the design’s.

The default’s import. The import type Default from './default' is the default’s, and the default’s is the type-only’s.

import type Default from './default';

The import type Default is the default’s, and the default’s is the type-only’s. The two are the pair, and the pair is the pattern’s.

The namespace’s import. The import type * as Types from './types' is the namespace’s, and the namespace’s is the type-only’s.

import type * as Types from './types';

The import type * as Types is the namespace’s, and the namespace’s is the type-only’s. The two are the pair, and the pair is the pattern’s.

The named’s import. The import type { User, Role } from './user' is the named’s, and the named’s is the type-only’s.

import type { User, Role } from './user';

The import type { User, Role } is the named’s, and the named’s is the type-only’s. The two are the pair, and the pair is the pattern’s.

Why the import type matters for the mixed’s. The import type is the all’s, and the all’s is the type-only’s. The mixed’s is the inline’s, and the inline’s is the import { type User, greet }‘s. The two are the pair, and the pair is the distinction’s.

Why the import type should be the statement’s. The import type should be the statement’s, and the statement’s is the top’s. The import type is the not the inline’s, and the inline’s is the type modifier’s. The two are the pair, and the pair is the design’s.

Why the import type matters for the bundler’s tree-shaking. The import type is the no-runtime’s, and the no-runtime’s is the tree-shaking’s. The bundler’s removes the type-only’s, and the type-only’s is the output’s. The two are the pair, and the pair is the optimization’s.


The inline’s type modifier

The import { type User, greet } from './user' is the inline’s, and the User is the type’s while the greet is the value’s.

import { type User, greet } from './user';

function process(user: User): string {
  return greet(user);
}

The import { type User, greet } is the inline’s, and the inline’s is the mixed’s. The User is the type’s, and the greet is the value’s. The two are the pair, and the pair is the distinction’s.

Why the inline’s matters. The inline’s is the mixed’s, and the mixed’s is the common’s. The module’s exports the type’s and the value’s, and the consumer’s imports the both’s. The two are the pair, and the pair is the pattern’s.

The type’s per-specifier. The import { type User, type Role, greet } is the per-specifier’s, and the per-specifier’s is the explicit’s.

import { type User, type Role, greet } from './user';

The type User, the type Role are the per-specifier’s, and the greet is the value’s. The two are the pair, and the pair is the pattern’s.

Why the per-specifier matters. The per-specifier is the explicit’s, and the explicit’s is the intent’s. The type modifier is the specifier’s, and the specifier’s is the granular’s. The two are the pair, and the pair is the design’s.

The default’s inline. The import { default as type User }‘s is the rare’s, and the rare’s is the default’s. The two are the pair, and the pair is the pattern’s.

Why the inline’s matters for the readability. The inline’s is the readability’s, and the readability’s is the intent’s. The type modifier is the reader’s, and the reader’s is the clear’s. The two are the pair, and the pair is the communication’s.

Why the inline’s should be the sparing. The inline’s should be the sparing, and the sparing’s is the mixed’s. The import type is the separate’s, and the separate’s is the all’s. The two are the pair, and the pair is the design’s.

Why the inline’s matters for the compiler. The inline’s is the compiler’s, and the compiler’s is the erase’s. The compiler erases the type-marked’s, and the type-marked’s is the output’s. The two are the pair, and the pair is the design’s.


The export type

The export type { User } re-exports the type’s only, and the export { type User } is the inline’s.

// The type-only's export
export type { User } from './user';

// The inline's export
export { type User, greet } from './user';

The export type { User } is the type-only’s, and the type-only’s is the re-export’s. The export { type User, greet } is the inline’s, and the inline’s is the mixed’s. The two are the pair, and the pair is the distinction’s.

Why the export type matters. The export type is the type-only’s, and the type-only’s is the barrel’s. The barrel’s re-exports the type’s, and the type’s is the erased’s. The two are the pair, and the pair is the design’s.

The barrel’s pattern. The index.ts‘s is the barrel’s, and the barrel’s is the re-export’s.

// index.ts
export type { User } from './user';
export type { Role } from './role';
export { greet } from './greet';

The export type { User }, the export type { Role }, the export { greet } are the barrel’s, and the barrel’s is the re-export’s. The two are the pair, and the pair is the pattern’s.

Why the barrel’s matters. The barrel’s is the convenience’s, and the convenience’s is the import’s. The import { User, greet } from '@app/shared' is the barrel’s, and the barrel’s is the single’s. The two are the pair, and the pair is the ergonomics’s.

Why the export type matters for the tree-shaking. The export type is the type-only’s, and the type-only’s is the tree-shaking’s. The bundler’s removes the type-only’s, and the type-only’s is the output’s. The two are the pair, and the pair is the optimization’s.

Why the export type should be the explicit. The export type should be the explicit, and the explicit’s is the verbatimModuleSyntax‘s. The export type is the requirement’s, and the requirement’s is the enforcement’s. The two are the pair, and the pair is the discipline’s.

Why the export type‘s inline matters. The export type‘s inline is the export { type User }‘s, and the inline’s is the mixed’s. The two are the pair, and the pair is the pattern’s.

Why the export type matters for the isolatedModules. The export type is the isolatedModules’s, and the isolatedModules’s is the file-by-file’s. The export { SomeType } is the error’s, and the export type { SomeType } is the fix’s. The two are the pair, and the pair is the design’s.


The verbatimModuleSyntax

The verbatimModuleSyntax: true requires the explicit’s type modifier for the type-only’s imports and exports.

{
  "compilerOptions": {
    "verbatimModuleSyntax": true
  }
}

The verbatimModuleSyntax: true is the flag’s, and the flag’s is the explicit’s. The verbatimModuleSyntax requires the import type and the export type, and the two are the enforcement’s. The two are the pair, and the pair is the design’s.

Why the verbatimModuleSyntax matters. The verbatimModuleSyntax is the modern’s, and the modern’s is the TypeScript 5.0’s. The verbatimModuleSyntax replaces the importsNotUsedAsValues and the preserveValueImports, and the replacement’s is the cleaner’s. The two are the pair, and the pair is the modern’s.

Why the verbatimModuleSyntax‘s enforcement matters. The verbatimModuleSyntax‘s enforcement is the safety’s, and the safety’s is the no-ambiguity’s. The import { User } without the type is the error’s, and the import type { User } is the fix’s. The two are the pair, and the pair is the design’s.

Why the verbatimModuleSyntax‘s emit matters. The verbatimModuleSyntax‘s emit is the verbatim’s, and the verbatim’s is the as-written’s. The compiler emits the imports as the written’s, and the written’s is the output’s. The two are the pair, and the pair is the predictability’s.

Why the verbatimModuleSyntax‘s CommonJS matters. The verbatimModuleSyntax‘s CommonJS is the import = require‘s, and the import = require‘s is the CommonJS’s. The ESM’s is the import‘s, and the import‘s is the ESM’s. The two are the pair, and the pair is the format’s.

Why the verbatimModuleSyntax matters for the bundler. The verbatimModuleSyntax is the bundler’s, and the bundler’s is the Vite’s and the esbuild’s. The bundler’s is the file-by-file’s, and the file-by-file’s is the isolatedModules’s. The two are the pair, and the pair is the performance’s.

Why the verbatimModuleSyntax should be the default. The verbatimModuleSyntax should be the default, and the default’s is the modern’s. The TypeScript 5.0’s is the verbatimModuleSyntax‘s, and the verbatimModuleSyntax‘s is the standard’s. The two are the pair, and the pair is the recommendation’s.

Why the verbatimModuleSyntax‘s migration matters. The verbatimModuleSyntax‘s migration is the importsNotUsedAsValues‘s, and the importsNotUsedAsValues‘s is the legacy’s. The verbatimModuleSyntax is the modern’s, and the modern’s is the fix’s. The two are the pair, and the pair is the migration’s.

Why the verbatimModuleSyntax matters for the isolatedModules. The verbatimModuleSyntax is the isolatedModules’s, and the isolatedModules’s is the file-by-file’s. The two are the pair, and the pair is the modern’s.


The isolatedModules

The isolatedModules: true requires the file-by-file’s transpilation, and the type-only’s import is the requirement’s.

{
  "compilerOptions": {
    "isolatedModules": true
  }
}

The isolatedModules: true is the flag’s, and the flag’s is the file-by-file’s. The isolatedModules catches the errors’s, and the errors’s is the export { SomeType }‘s. The two are the pair, and the pair is the design’s.

Why the isolatedModules matters. The isolatedModules is the transpiler’s, and the transpiler’s is the Babel’s, the SWC’s, the esbuild’s. The transpiler’s is the file-by-file’s, and the file-by-file’s is the isolation’s. The two are the pair, and the pair is the performance’s.

Why the isolatedModules‘s errors matter. The isolatedModules‘s errors are the type-only’s, and the type-only’s is the export type‘s. The export { SomeType } is the error’s, and the export type { SomeType } is the fix’s. The two are the pair, and the pair is the design’s.

Why the isolatedModules‘s const enum matters. The isolatedModules‘s const enum is the error’s, and the error’s is the cross-file’s. The const enum is the inlining’s, and the inlining’s is the file-by-file’s. The two are the pair, and the pair is the design’s.

Why the isolatedModules‘s namespace matters. The isolatedModules‘s namespace is the error’s, and the error’s is the runtime’s. The namespace’s is the value’s, and the value’s is the runtime’s. The two are the pair, and the pair is the design’s.

Why the isolatedModules matters for the bundler. The isolatedModules is the bundler’s, and the bundler’s is the Vite’s. The Vite’s is the file-by-file’s, and the file-by-file’s is the fast’s. The two are the pair, and the pair is the performance’s.

Why the isolatedModules should be the default. The isolatedModules should be the default, and the default’s is the modern’s. The Vite’s is the standard’s, and the standard’s is the bundler’s. The two are the pair, and the pair is the recommendation’s.

Why the isolatedModules‘s verbatimModuleSyntax matters. The isolatedModules‘s verbatimModuleSyntax is the pair’s, and the pair’s is the modern’s. The two are the pair, and the pair is the design’s.

Why the isolatedModules matters for the editor. The isolatedModules is the editor’s, and the editor’s is the language service’s. The editor’s is the fast’s, and the fast’s is the productivity’s. The two are the pair, and the pair is the performance’s.


The importsNotUsedAsValues‘s legacy

The importsNotUsedAsValues is the legacy’s, and the verbatimModuleSyntax is the modern’s.

The importsNotUsedAsValues‘s values. The remove, the preserve, the error. The three are the legacy’s, and the legacy’s is the deprecated’s.

// The legacy's (deprecated)
{
  "compilerOptions": {
    "importsNotUsedAsValues": "error"
  }
}

The importsNotUsedAsValues: "error" is the legacy’s, and the legacy’s is the deprecated’s. The verbatimModuleSyntax is the modern’s, and the modern’s is the fix’s. The two are the pair, and the pair is the migration’s.

Why the importsNotUsedAsValues matters. The importsNotUsedAsValues is the legacy’s, and the legacy’s is the context’s. The remove is the default’s, and the default’s is the erased’s. The two are the pair, and the pair is the history’s.

Why the verbatimModuleSyntax replaced it. The verbatimModuleSyntax replaced the importsNotUsedAsValues and the preserveValueImports, and the replacement’s is the simpler’s. The verbatimModuleSyntax is the single’s, and the single’s is the design’s. The two are the pair, and the pair is the modern’s.

Why the migration matters. The migration is the importsNotUsedAsValues‘s to the verbatimModuleSyntax‘s, and the verbatimModuleSyntax‘s is the modern’s. The two are the pair, and the pair is the upgrade’s.

Why the legacy’s removal matters. The legacy’s removal is the TypeScript 5.5’s, and the TypeScript 5.5’s is the deprecated’s. The verbatimModuleSyntax is the modern’s, and the modern’s is the fix’s. The two are the pair, and the pair is the version’s.

Why the preserveValueImports matters. The preserveValueImports is the legacy’s, and the legacy’s is the side-effect’s. The verbatimModuleSyntax is the modern’s, and the modern’s is the replacement’s. The two are the pair, and the pair is the migration’s.

Why the legacy’s context matters. The legacy’s context is the history’s, and the history’s is the documentation’s. The verbatimModuleSyntax is the modern’s, and the modern’s is the recommendation’s. The two are the pair, and the pair is the guide’s.

Why the legacy’s removal’s impact matters. The legacy’s removal’s impact is the migration’s, and the migration’s is the codebase’s. The two are the pair, and the pair is the upgrade’s.


The patterns

The patterns are the common’s, and the common’s is the practice’s.

The pattern 1: the type-only’s import. The import type { User } from './user' is the type-only’s, and the type-only’s is the function’s parameter’s.

import type { User } from './user';

function greet(user: User): string {
  return `Hello, ${user.name}`;
}

The import type { User } is the type-only’s, and the type-only’s is the erased’s. The two are the pair, and the pair is the pattern’s.

Why the pattern 1 matters. The pattern 1 is the most’s, and the most’s is the common’s. The import type is the explicit’s, and the explicit’s is the intent’s. The two are the pair, and the pair is the design’s.

The pattern 2: the inline’s type. The import { type User, greet } is the inline’s, and the inline’s is the mixed’s.

import { type User, greet } from './user';

The import { type User, greet } is the inline’s, and the inline’s is the mixed’s. The two are the pair, and the pair is the pattern’s.

Why the pattern 2 matters. The pattern 2 is the mixed’s, and the mixed’s is the common’s. The inline’s is the explicit’s, and the explicit’s is the intent’s. The two are the pair, and the pair is the design’s.

The pattern 3: the barrel’s type. The export type { User } from './user' is the barrel’s, and the barrel’s is the re-export’s.

// index.ts
export type { User } from './user';
export { greet } from './greet';

The export type { User }, the export { greet } are the barrel’s, and the barrel’s is the re-export’s. The two are the pair, and the pair is the pattern’s.

Why the pattern 3 matters. The pattern 3 is the barrel’s, and the barrel’s is the convenience’s. The export type is the explicit’s, and the explicit’s is the tree-shaking’s. The two are the pair, and the pair is the design’s.

The pattern 4: the verbatimModuleSyntax. The verbatimModuleSyntax: true is the enforcement’s, and the enforcement’s is the explicit’s.

{
  "compilerOptions": {
    "verbatimModuleSyntax": true
  }
}

The verbatimModuleSyntax: true is the enforcement’s, and the enforcement’s is the explicit’s. The two are the pair, and the pair is the pattern’s.

Why the pattern 4 matters. The pattern 4 is the modern’s, and the modern’s is the TypeScript 5.0’s. The verbatimModuleSyntax is the standard’s, and the standard’s is the recommendation’s. The two are the pair, and the pair is the design’s.

The pattern 5: the isolatedModules. The isolatedModules: true is the file-by-file’s, and the file-by-file’s is the bundler’s.

{
  "compilerOptions": {
    "isolatedModules": true
  }
}

The isolatedModules: true is the file-by-file’s, and the file-by-file’s is the bundler’s. The two are the pair, and the pair is the pattern’s.

Why the pattern 5 matters. The pattern 5 is the bundler’s, and the bundler’s is the modern’s. The isolatedModules is the standard’s, and the standard’s is the Vite’s. The two are the pair, and the pair is the design’s.

Why the patterns matter. The patterns are the vocabulary’s, and the vocabulary’s is the fluency’s. The five are the common’s, and the common’s is the practice’s. The two are the pair, and the pair is the skill’s.


Complete Example Session

// ============================================
// PART 1: THE TYPE-ONLY'S IMPORT
// ============================================

// user.ts
export interface User {
  id: string;
  name: string;
}

export function greet(user: User): string {
  return `Hello, ${user.name}`;
}

// app.ts
import type { User } from './user';

function process(user: User): string {
  return user.name;
}

// ============================================
// PART 2: THE INLINE'S TYPE
// ============================================

import { type User, greet } from './user';

function process2(user: User): string {
  return greet(user);
}

// ============================================
// PART 3: THE EXPORT TYPE
// ============================================

// index.ts (the barrel)
export type { User } from './user';
export { greet } from './user';

// ============================================
// PART 4: THE VERBATIM MODULE SYNTAX
// ============================================

// tsconfig.json
{
  "compilerOptions": {
    "verbatimModuleSyntax": true
  }
}

// The error:
// import { User } from './user';  // ❌ the User is a type

// The fix:
import type { User } from './user';  // ✅

// ============================================
// PART 5: THE ISOLATED MODULES
// ============================================

// tsconfig.json
{
  "compilerOptions": {
    "isolatedModules": true
  }
}

// The error:
// export { User };  // ❌ the User is a type

// The fix:
export type { User };  // ✅

// ============================================
// PART 6: THE EMITTED JAVASCRIPT
// ============================================

// The source:
import type { User } from './user';
import { greet } from './user';

// The emitted:
// import { greet } from './user';
// (The type-only's import is erased.)

// ============================================
// PART 7: THE BUNDLER'S TREE-SHAKING
// ============================================

// The type-only's import is the no-runtime's,
// and the bundler removes the unused's.

// ============================================
// PART 8: THE BARREL'S PATTERN
// ============================================

// shared/index.ts
export type { User, Role } from './types';
export { greet } from './greet';
export { formatDate } from './date';

// The consumer:
import { type User, greet, formatDate } from '@app/shared';

// ============================================
// PART 9: THE MIGRATION
// ============================================

// The legacy:
// "importsNotUsedAsValues": "error"

// The modern:
// "verbatimModuleSyntax": true

// ============================================
// PART 10: WHAT NOT TO DO
// ============================================

// Don't use the ambiguous's import
import { User } from './user';  // the ambiguous's             // ⚠️

// Don't forget the type modifier in the barrel
export { User } from './user';  // the isolatedModules's error  // ⚠️

// Don't use the const enum with the isolatedModules
const enum Color { Red }  // the error's                      // ⚠️

// Don't mix the import type and the import
import type { User } from './user';  // the separate's        // ⚠️

// Don't forget the verbatimModuleSyntax
// The ambiguity's.

// Don't use the importsNotUsedAsValues
// The legacy's.

The ten parts cover the type-only’s import, the inline’s type, the export type, the verbatimModuleSyntax, the isolatedModules, the emitted JavaScript, the bundler’s tree-shaking, the barrel’s pattern, the migration, and the anti-patterns.


Quick Reference

The Type-Only’s Forms

FormPurpose
The import type { User }The named’s type-only
The import type DefaultThe default’s type-only
The import type * as TypesThe namespace’s type-only
The import { type User, greet }The inline’s mixed
The export type { User }The re-export’s type-only
The export { type User, greet }The inline’s mixed

The Compiler Options

OptionPurpose
The verbatimModuleSyntaxThe explicit’s enforcement
The isolatedModulesThe file-by-file’s
The importsNotUsedAsValuesThe legacy’s (deprecated)
The preserveValueImportsThe legacy’s (deprecated)

The verbatimModuleSyntax‘s Requirements

The sourceThe required’s
The type’s importThe import type
The type’s exportThe export type
The value’s importThe plain’s import
The value’s exportThe plain’s export

The isolatedModules‘s Errors

The errorThe fix
The export { SomeType }The export type { SomeType }
The const enumThe plain’s enum
The namespace’sThe module’s
The import { SomeType }The import type { SomeType }

The Emitted JavaScript

The sourceThe emitted
The import type { User }The nothing
The import { greet }The import { greet }
The export type { User }The nothing
The export { greet }The export { greet }

Best Practices

✅ Do This:

// Use the import type for the types
import type { User } from './user';                            // ✅
// Use the inline's type for the mixed
import { type User, greet } from './user';                     // ✅
// Use the export type for the barrel
export type { User } from './user';                            // ✅
// Use the verbatimModuleSyntax
{ "compilerOptions": { "verbatimModuleSyntax": true } }        // ✅
// Use the isolatedModules
{ "compilerOptions": { "isolatedModules": true } }             // ✅
// Use the type modifier per-specifier
import { type User, type Role, greet } from './user';          // ✅
// Use the barrel's type export
export type { User, Role } from './types';                     // ✅

❌ Don’t Do This:

// Don't use the ambiguous's import
import { User } from './user';  // the type's or the value's   // ⚠️
// Don't forget the type modifier in the barrel
export { User } from './user';  // the isolatedModules's error // ⚠️
// Don't use the const enum with the isolatedModules
const enum Color { Red }  // the error's                       // ⚠️
// Don't mix the import type and the import
import type { User } from './user';  // the separate's         // ⚠️
// Don't forget the verbatimModuleSyntax
// The ambiguity's.
// Don't use the importsNotUsedAsValues
{ "importsNotUsedAsValues": "error" }  // the legacy's         // ⚠️

Common Pitfalls

PitfallProblemSolution
The ambiguous’s importThe transpiler’s errorThe import type
The missing export typeThe isolatedModules‘s errorThe export type
The const enumThe isolatedModules‘s errorThe plain’s enum
The mixed’sThe verboseThe inline’s type
The legacy’s optionThe deprecatedThe verbatimModuleSyntax
The missing’s typeThe bundler’sThe explicit’s
The namespace’sThe isolatedModules‘s errorThe module’s
The barrel’s valueThe type’sThe export type

Real-World Examples

1. The type-only’s import

import type { User } from './user';

2. The inline’s type

import { type User, greet } from './user';

3. The per-specifier’s

import { type User, type Role, greet } from './user';

4. The export type

export type { User } from './user';

5. The inline’s export

export { type User, greet } from './user';

6. The barrel

export type { User, Role } from './types';
export { greet } from './greet';

7. The verbatimModuleSyntax

{ "compilerOptions": { "verbatimModuleSyntax": true } }

8. The isolatedModules

{ "compilerOptions": { "isolatedModules": true } }

9. The namespace’s type-only

import type * as Types from './types';

10. The default’s type-only

import type Default from './default';

Visual: The Type-Only’s Import

┌──────────────────────────────────────────────────────────┐
│  THE SOURCE                                              │
│    import type { User } from './user';                   │
│    import { greet } from './user';                       │
│                                                          │
│         │  The compiler                                  │
│         ▼                                                │
│                                                          │
│  THE EMITTED                                             │
│    import { greet } from './user';                       │
│    (The type-only's is erased.)                          │
│                                                          │
│  The type's is the compile-time's, and the value's is    │
│  the runtime's.                                          │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: The verbatimModuleSyntax

┌──────────────────────────────────────────────────────────┐
│  WITHOUT verbatimModuleSyntax                            │
│    import { User } from './user';                        │
│      The compiler's guess: the type's.                   │
│      The emitted's: the nothing.                         │
│    The transpiler's: the guess's, and the guess's is     │
│    the error's.                                          │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  WITH verbatimModuleSyntax                               │
│    import { User } from './user';  // ❌                 │
│      The error: the type's must be the explicit's.       │
│    import type { User } from './user';  // ✅            │
│      The explicit's, and the erased's.                   │
│                                                          │
│  The verbatimModuleSyntax is the enforcement's.          │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: The isolatedModules

┌──────────────────────────────────────────────────────────┐
│  THE TRANSPILER'S (the Vite, the esbuild, the SWC)       │
│    The file-by-file's transpilation.                     │
│    The type's is the separate's.                         │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  THE isolatedModules'S                                   │
│    The export type's is the explicit's.                  │
│    The const enum's is the error's.                      │
│    The namespace's is the error's.                       │
│                                                          │
│  The isolatedModules is the file-by-file's requirement.  │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: The Barrel’s Pattern

┌──────────────────────────────────────────────────────────┐
│  THE BARREL (the index.ts)                               │
│    export type { User, Role } from './types';            │
│    export { greet } from './greet';                      │
│                                                          │
│  THE CONSUMER                                            │
│    import { type User, greet } from '@app/shared';       │
│                                                          │
│  THE TREE-SHAKING                                        │
│    The type-only's is erased, and the value's is the     │
│    kept's.                                               │
│                                                          │
│  The barrel's is the convenience's, and the type-only's  │
│  is the optimization's.                                  │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: The Migration

┌──────────────────────────────────────────────────────────┐
│  THE LEGACY                                              │
│    "importsNotUsedAsValues": "error"                     │
│    "preserveValueImports": true                          │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  THE MODERN                                              │
│    "verbatimModuleSyntax": true                          │
│                                                          │
│  The verbatimModuleSyntax replaces the two, and the two  │
│  are the deprecated's.                                   │
│                                                          │
└──────────────────────────────────────────────────────────┘

Summary

ItemValue
The import typeThe type-only’s import
The export typeThe type-only’s export
The inline’s typeThe mixed’s
The verbatimModuleSyntaxThe explicit’s enforcement
The isolatedModulesThe file-by-file’s
The importsNotUsedAsValuesThe legacy’s
The preserveValueImportsThe legacy’s
The erased’sThe type-only’s
The tree-shaking’sThe bundler’s

Key takeaways:

  • The type-only’s import brings a type without a runtime’s dependency — the compiler erases it, and the emitted JavaScript has no trace of it
  • The import type is the explicit’s, and the inline’s type is the mixed’s — the import { type User, greet } is the per-specifier’s
  • The export type re-exports the type’s only — the barrel’s is the common’s, and the export type is the tree-shaking’s
  • The verbatimModuleSyntax requires the explicit’s type modifier — it prevents the compiler’s guessing, and it is the TypeScript 5.0’s
  • The isolatedModules requires the file-by-file’s transpilation — the Vite, the esbuild, the SWC, the Babel are the file-by-file’s
  • The type-only’s import is erased, and the value’s is the kept’s — the emitted JavaScript has the value’s only
  • The bundler’s tree-shaking is the type-only’s benefit — the no-runtime’s is the unused’s removal’s
  • The importsNotUsedAsValues and the preserveValueImports are the legacy’s — the verbatimModuleSyntax is the modern’s replacement
  • The const enum and the namespace’s are the isolatedModules‘s errors — the plain’s enum and the module’s are the fixes
  • The type-only’s import should be the default — the explicit’s is the intent’s, and the intent’s is the clarity’s

Remember: The type-only’s import and export are the explicit’s, and the explicit’s is the modern’s. The import type and the export type are the erased’s, and the verbatimModuleSyntax is the enforcement’s. The isolatedModules is the file-by-file’s, and the bundler’s is the tree-shaking’s. The type-only’s is the no-runtime’s, and the no-runtime’s is the output’s. The type-only’s is the discipline’s, and the discipline’s is the practice’s.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!