Skip to content

Commit d6d6d9b

Browse files
committed
Twoslashed 15
1 parent 9db3b4c commit d6d6d9b

File tree

2 files changed

+243
-116
lines changed

2 files changed

+243
-116
lines changed

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

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ Sometimes you'll be using other tools than `tsc` to turn your TypeScript into Ja
157157

158158
Consider this example of an `AlbumFormat` enum that has been created with `declare const`:
159159

160-
```tsx
160+
```ts twoslash
161+
// @errors: 2748
162+
// @isolatedModules: true
161163
declare const enum AlbumFormat {
162164
CD,
163165
Vinyl,
@@ -171,17 +173,7 @@ Recall that the `declare` keyword will place `const enum` in an ambient context,
171173

172174
When `isolatedModules` is disabled, this code will compile without any errors.
173175

174-
However, when `isolatedModules` is enabled, the `AlbumFormat` enum will not be erased and TypeScript will raise an error:
175-
176-
```tsx
177-
// hovering over AlbumFormat.Vinyl shows:
178-
Cannot access ambient const enums when 'isolatedModules' is enabled.
179-
180-
// index.js after transpilation
181-
"use strict";
182-
Object.defineProperty(exports, "__esModule", { value: true });
183-
const largestPhysicalSize = AlbumFormat.Vinyl;
184-
```
176+
However, when `isolatedModules` is enabled, the `AlbumFormat` enum will not be erased and TypeScript will raise an error.
185177

186178
This is because only `tsc` has enough context to understand what value `AlbumFormat.Vinyl` should have. TypeScript checks your entire project at once, and stores the values for `AlbumFormat` in memory.
187179

@@ -256,22 +248,48 @@ TypeError: Cannot read property 'toUpperCase' of undefined
256248

257249
By setting `noUncheckedIndexedAccess` to `true`, TypeScript will infer the type of every indexed access to be `T | undefined` instead of just `T`. In this case, every entry in `egoMirror.tracks` would be of type `string | undefined`:
258250

259-
```tsx
251+
```ts twoslash
252+
// @noUncheckedIndexedAccess: true
253+
interface VinylSingle {
254+
title: string;
255+
artist: string;
256+
tracks: string[];
257+
}
258+
259+
const egoMirror: VinylSingle = {
260+
title: "Ego / Mirror",
261+
artist: "Burial / Four Tet / Thom Yorke",
262+
tracks: ["Ego", "Mirror"],
263+
};
264+
265+
// ---cut---
266+
260267
const ego = egoMirror.tracks[0];
268+
// ^?
261269
const mirror = egoMirror.tracks[1];
262270
const nonExistentTrack = egoMirror.tracks[3];
263-
264-
// hovering over ego shows:
265-
// const ego: string | undefined
266271
```
267272

268273
However, because the types of each of the tracks are now `string | undefined`, we have errors when attempting to call `toUpperCase` even for the valid tracks:
269274

270-
```typescript
271-
console.log(ego.toUpperCase()); // red squiggly line under ego
275+
```ts twoslash
276+
// @errors: 18048
277+
// @noUncheckedIndexedAccess: true
278+
interface VinylSingle {
279+
title: string;
280+
artist: string;
281+
tracks: string[];
282+
}
283+
284+
const egoMirror: VinylSingle = {
285+
title: "Ego / Mirror",
286+
artist: "Burial / Four Tet / Thom Yorke",
287+
tracks: ["Ego", "Mirror"],
288+
};
272289

273-
// hovering over ego shows
274-
'ego' is possibly 'undefined'
290+
const ego = egoMirror.tracks[0];
291+
// ---cut---
292+
console.log(ego.toUpperCase()); // red squiggly line under ego
275293
```
276294

277295
This means that we have to handle the possibility of `undefined` values when accessing array or object indices.
@@ -524,21 +542,22 @@ If we keep `album.ts` the same, TypeScript will look up the directories for the
524542

525543
For example, consider this file `hello.cts` that uses the `export default` syntax:
526544

527-
```tsx
545+
```ts twoslash
546+
// @errors: 1286
547+
// @verbatimModuleSyntax: true
548+
// @module: NodeNext
549+
// @moduleResolution: NodeNext
550+
// @filename hello.cts
551+
528552
// hello.cts
529553
const hello = () => {
530554
console.log("Hello!");
531555
};
532556

533-
export { hello }; // red squiggly line under export { hello }
557+
export { hello };
534558
```
535559

536-
When `verbatimModuleSyntax` is enabled, TypeScript will show an error under the `export default` line that tells us we're mixing the syntaxes together:
537-
538-
```tsx
539-
// hovering over export { hello } shows:
540-
ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
541-
```
560+
When `verbatimModuleSyntax` is enabled, TypeScript will show an error under the `export default` line that tells us we're mixing the syntaxes together.
542561

543562
In order to fix the issue, we need to use the `export =` syntax instead:
544563

@@ -555,11 +574,14 @@ This will compile down to `module.exports = { hello }` in the emitted JavaScript
555574

556575
The warnings will show when trying to use an ESM import as well:
557576

558-
```tsx
559-
import { z } from "zod"; // rsl under import statement
577+
```ts twoslash
578+
// @errors: 1286
579+
// @verbatimModuleSyntax: true
580+
// @module: NodeNext
581+
// @moduleResolution: NodeNext
582+
// @filename hello.cts
560583

561-
// hovering over the import shows:
562-
// ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
584+
import { z } from "zod";
563585
```
564586

565587
Here, the fix is to use `require` instead of `import`:
@@ -822,9 +844,10 @@ declare const ONLY_ON_SERVER: string;
822844

823845
Trying to use `ONLY_ON_SERVER` in a file that's part of the `client` configuration will result in an error:
824846

825-
```tsx
847+
```ts twoslash
848+
// @errors: 2304
826849
// inside client/index.ts
827-
console.log(ONLY_ON_SERVER); // red squiggly line under ONLY_ON_SERVER
850+
console.log(ONLY_ON_SERVER);
828851
```
829852

830853
This feature is useful when dealing with environment-specific variables or globals that come from testing tools like Jest or Cypress, and avoids polluting the global scope.

0 commit comments

Comments
 (0)