Skip to content

Commit d22aa83

Browse files
committed
Twoslashed 02
1 parent f90f05b commit d22aa83

File tree

1 file changed

+47
-64
lines changed

1 file changed

+47
-64
lines changed

book-content/chapters/02-ide-superpowers.md

Lines changed: 47 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,14 @@ Sometimes TypeScript will warn you about things that will definitely fail at run
101101

102102
For example, consider the following code:
103103

104-
```typescript
104+
```ts twoslash
105+
// @errors: 18047
105106
const a = null;
106107

107-
a.toString(); // red squiggly line under `a`
108-
```
109-
110-
TypeScript tells us that there is a problem with `a`. Hovering over it shows the following error message:
111-
112-
```
113-
'a' is possibly 'null'.
108+
a.toString();
114109
```
115110

116-
This tells us where the problem is, but it doesn't necessarily tell us what the problem is. In this case, we need to stop and think about why we can't call `toString()` on `null`. If we do, it will throw an error at runtime.
111+
TypeScript tells us that there is a problem with `a`. This tells us where the problem is, but it doesn't necessarily tell us what the problem is. In this case, we need to stop and think about why we can't call `toString()` on `null`. If we do, it will throw an error at runtime.
117112

118113
```
119114
Uncaught TypeError: Cannot read properties of null (reading 'toString').
@@ -127,10 +122,11 @@ Not everything TypeScript warns us about will actually fail at runtime.
127122

128123
Take a look at this example where we're assigning a property to an empty object:
129124

130-
```typescript
125+
```ts twoslash
126+
// @errors: 2339
131127
const obj = {};
132128

133-
const result = obj.foo; // red squiggly line under `foo`
129+
const result = obj.foo;
134130
```
135131

136132
TypeScript draws a red squiggly line below `foo`. But if we think about it, this code won't actually cause an error at runtime. We're trying to assign a property that doesn't exist in this object: `foo`. This won't error, it will just mean that result is undefined.
@@ -141,37 +137,28 @@ It's best to think of TypeScript's rules as opinionated. They are a collection o
141137

142138
### Warnings Close to the Source of the Problem
143139

144-
<!-- TODO Consider moving this and the next section to later, perhaps the weird parts -->
145-
146140
TypeScript will try to give you warnings as close to the source of the problem as possible.
147141

148142
Let's take a look at an example.
149143

150-
```typescript
144+
```ts twoslash
145+
// @errors: 2561
151146
type Album = {
152147
artist: string;
153148
title: string;
154149
year: number;
155150
};
156151

157152
const album: Album = {
158-
artsist: "Television", // red squiggly line under `artsist`
153+
artsist: "Television",
159154
title: "Marquee Moon",
160155
year: 1977,
161156
};
162157
```
163158

164159
We define an 'Album' type - an object with three properties. Then, we say that const album needs to be of that type via `const album: Album`. Don't worry if you don't understand all the syntax yet - we'll cover it all later.
165160

166-
Can you see the problem? There's a typo of the `artist` property when creating an album. Hovering over `artsist` shows the following error message:
167-
168-
```
169-
Type '{ artsist: string; title: string; year: number; }' is not assignable to type 'Album'.
170-
171-
Object literal may only specify known properties, but 'artsist' does not exist in type 'Album'. Did you mean to write 'artist'?
172-
```
173-
174-
That's because we've said that the `album` variable needs to be of type `Album`, but we've misspelled `artist` as `artsist`. TypeScript is telling us that we've made a mistake, and even suggests the correct spelling.
161+
Can you see the problem? There's a typo of the `artist` property when creating an album. That's because we've said that the `album` variable needs to be of type `Album`, but we've misspelled `artist` as `artsist`. TypeScript is telling us that we've made a mistake, and even suggests the correct spelling.
175162

176163
### Dealing With Multi-Line Errors
177164

@@ -193,26 +180,28 @@ Don't worry about the syntax for now - we'll cover it later. The important thing
193180

194181
Now, let's call `logUserJobTitle` with a user object where the `job.title` is a number, not a string.
195182

196-
```typescript
183+
```ts twoslash
184+
// @errors: 2345
185+
const logUserJobTitle = (user: {
186+
job: {
187+
title: string;
188+
};
189+
}) => {
190+
console.log(user.job.title);
191+
};
192+
193+
// ---cut---
197194
const exampleUser = {
198195
job: {
199196
title: 123,
200197
},
201198
};
202199

203-
logUserJobTitle(exampleUser); // red squiggly line under `exampleUser`
200+
logUserJobTitle(exampleUser);
204201
```
205202

206203
It might seem like TypeScript should give us an error on `title` in the `exampleUser` object. But instead, it gives us an error on the `exampleUser` variable itself.
207204

208-
Hovering over `exampleUser` shows the following error message:
209-
210-
```
211-
Argument of type '{ job: { title: number; }; }' is not assignable to parameter of type '{ job: { title: string; }; }'.
212-
The types of 'job.title' are incompatible between these types.
213-
Type 'number' is not assignable to type 'string'.
214-
```
215-
216205
It's multiple lines long, which can feel pretty scary. A good rule of thumb with multi-line errors is to start at the bottom:
217206

218207
```
@@ -239,12 +228,9 @@ You can hover over more than just error messages. Any time you hover over a vari
239228

240229
In this example, we could hover over `thing` and see that it's of type `number`:
241230

242-
```typescript
231+
```ts twoslash
243232
let thing = 123;
244-
245-
// hovering over `thing` shows:
246-
247-
let thing: number;
233+
// ^?
248234
```
249235

250236
Hovering works for more involved examples as well. Here `otherObject` spreads in the properties of `otherThing` as well as adding `thing`:
@@ -256,28 +242,30 @@ let otherThing = {
256242

257243
const otherObject = {
258244
...otherThing,
259-
thing,
245+
thing: "abc",
260246
};
261247

262248
otherObject.thing;
263249
```
264250

265251
Hovering over `otherObject` will give us a computed readout of all of its properties:
266252

267-
```typescript
268-
// hovering over `otherObject` shows:
269-
270-
const otherObject: {
271-
thing: number;
272-
name: string;
253+
```ts twoslash
254+
let otherThing = {
255+
name: "Alice",
273256
};
274-
```
275257

276-
Depending on what you hover over, VS Code will show you different information. For example, hovering over `.thing` in `otherObject.thing` will show you the type of `thing`:
258+
const otherObject = {
259+
...otherThing,
260+
thing: "abc",
261+
};
277262

263+
// ---cut---
264+
console.log(otherObject);
265+
// ^?
278266
```
279-
(property) thing: number
280-
```
267+
268+
Depending on what you hover over, VS Code will show you different information. For example, hovering over `otherObject` will show you all of its properties, while hovering over `thing` will show you its type.
281269

282270
Get used to the ability to float around your codebase introspecting variables and declarations, because it's a great way to understand what the code is doing.
283271

@@ -287,8 +275,9 @@ Get used to the ability to float around your codebase introspecting variables an
287275

288276
In this code snippet we're trying to grab an element using `document.getElementById` with an ID of `12`. However, TypeScript is complaining.
289277

290-
```javascript
291-
let element = document.getElementById(12); // red squiggly line under 12
278+
```ts twoslash
279+
// @errors: 2345
280+
let element = document.getElementById(12);
292281
```
293282

294283
How can hovering help to determine what argument `document.getElementById` actually requires? And for a bonus point, what type is `element`?
@@ -311,17 +300,12 @@ In the case of `getElementById`, we can see that it requires a string as an argu
311300

312301
This tells us that we can fix the error by changing the argument to a string:
313302

314-
```typescript
303+
```ts twoslash
315304
let element = document.getElementById("12");
305+
// ^?
316306
```
317307

318-
We also know that `element`'s type will be what `document.getElementById` returns, which we can confirm by hovering over `element`:
319-
320-
```typescript
321-
// hovering over element shows:
322-
323-
const element: HTMLElement | null;
324-
```
308+
We also know that `element`'s type will be what `document.getElementById` returns, which we can confirm by hovering over `element`.
325309

326310
So, hovering in different places reveals different information. When I'm working in TypeScript, I hover constantly to get a better sense of what my code is doing.
327311

@@ -432,8 +416,6 @@ A TypeScript-enabled feature called 'Rename Symbol' allows you to do that with a
432416

433417
Let's take a look at an example.
434418

435-
<!-- We could convert this to an exercise? -->
436-
437419
```typescript
438420
const filterUsersById = (id: string) => {
439421
return users.filter((user) => user.id === id);
@@ -466,8 +448,9 @@ VS Code also offers a "Quick Fix" feature that can be used to run quick refactor
466448

467449
To open the Quick Fix menu, hit `Command + .`. If you do this on a line of code which references a value that hasn't been imported yet, a popup will show.
468450

469-
```typescript
470-
const triangle = new Triangle(); // red squiggly line under `Triangle`
451+
```ts twoslash
452+
// @errors: 2552
453+
const triangle = new Triangle();
471454
```
472455

473456
One of the options in the Quick Fix menu will be 'Add All Missing Imports'. Selecting this option will add all the missing imports to the top of the file.

0 commit comments

Comments
 (0)