Skip to content

Commit f7bb6de

Browse files
committed
Added section on import type
1 parent 3a3ce2f commit f7bb6de

File tree

1 file changed

+75
-5
lines changed

1 file changed

+75
-5
lines changed

book-content/chapters/14-configuring-typescript.md

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,17 +363,83 @@ This is because the bundler will take care of resolving the file paths and exten
363363

364364
This means that if you're using an external bundler or transpiler, you should use `module: "Preserve"` in your `tsconfig.json` file. This is also true if you're using a frontend framework like Next.js, Remix, Vite, or SvelteKit - it will handle the bundling for you.
365365

366-
## `import type`
366+
## Importing Types With `import type`
367367

368-
<!-- TODO -->
368+
When you're importing types from other files, TypeScript has some choices to make. Let's say you're importing a type of `Album` from `album.ts`:
369+
370+
```typescript
371+
// index.ts
372+
373+
import { Album } from "./album";
374+
```
375+
376+
What should the emitted JavaScript look like? We're only importing a type, which disappears at runtime. Should the import remain, but with the type removed?
377+
378+
```javascript
379+
// index.js
380+
381+
import {} from "./album";
382+
```
383+
384+
Or should the import be removed entirely?
385+
386+
These decisions matter, because modules can contain effects which run when they're first imported. For instance, `album.ts` might call a `console.log` statement:
387+
388+
```typescript
389+
// album.ts
390+
391+
export interface Album {
392+
title: string;
393+
artist: string;
394+
year: number;
395+
}
396+
397+
console.log("Imported album.ts");
398+
```
399+
400+
Now, if TypeScript removes (or, as they say in the TypeScript docs, elides) the import, the `console.log` statement won't run. This can be surprising if you're not expecting it.
401+
402+
The way TypeScript resolves this is with the `import type` syntax. If you're importing a type and you don't want the import to be emitted in the JavaScript, you can use `import type`:
403+
404+
```typescript
405+
// index.ts
406+
407+
import type { Album } from "./album";
408+
```
409+
410+
Now, only the type information is imported, and the import is removed from the emitted JavaScript:
411+
412+
```javascript
413+
// index.js
414+
415+
// No import statement
416+
```
369417

370418
### `import type { X }` vs `import { type X }`
371419

372-
<!-- TODO -->
420+
You can combine `import` and `type` in two ways. You can either mark the entire line as a type import:
421+
422+
```typescript
423+
import type { Album } from "./album";
424+
```
425+
426+
Or, if you want to combine runtime imports with type imports, you can mark the type itself as a type import:
427+
428+
```typescript
429+
import { type Album, createAlbum } from "./album";
430+
```
431+
432+
In this case, `createAlbum` will be imported as a runtime import, and `Album` will be imported as a type import.
433+
434+
In both cases, it's clear what will be removed from the emitted JavaScript. The first line will remove the entire import, and the second line will remove only the type import.
373435

374436
### `verbatimModuleSyntax` Enforces `import type`
375437

376-
<!-- TODO -->
438+
TypeScript has gone through various iterations of configuration options to support this behavior. `importsNotUsedAsValues` and `preserveValueImports` both tried to solve the problem. But since TypeScript 5.0, `verbatimModuleSyntax` is the recommended way to enforce `import type`.
439+
440+
The behavior described above, where imports are elided if they're only used for types, is what happens when `verbatimModuleSyntax` is set to `true`.
441+
442+
You might be wondering why it isn't part of the recommended set of options detailed above. The reason is that it also has some impact on how modules work in TypeScript - we'll talk about that in the next section.
377443

378444
## ESM and CommonJS
379445

@@ -387,10 +453,14 @@ This means that if you're using an external bundler or transpiler, you should us
387453

388454
<!-- TODO -->
389455

390-
#### `import X = require('x')`
456+
#### Importing and Exporting In CJS
457+
458+
`import X = require('x')`
391459

392460
<!-- TODO -->
393461

462+
#### When `verbatimModuleSyntax` Isn't Appropriate
463+
394464
## `noEmit`
395465

396466
The `noEmit` option in `tsconfig.json` tells TypeScript not to emit any JavaScript files when transpiling your TypeScript code.

0 commit comments

Comments
 (0)