diff --git a/book-content/chapters/04-essential-types-and-annotations.md b/book-content/chapters/04-essential-types-and-annotations.md index f677303..a6a4340 100644 --- a/book-content/chapters/04-essential-types-and-annotations.md +++ b/book-content/chapters/04-essential-types-and-annotations.md @@ -166,7 +166,8 @@ isReleased = "yes"; And also giving us autocomplete on the variable: ```ts -albumTitle.toUpper; // shows `toUpperCase` in autocomplete +// prettier-ignore +albumTitle.toUpper // shows `toUpperCase` in autocomplete ``` This is an extremely powerful part of TypeScript. It means that you can mostly _not_ annotate variables and still have your IDE know what type things are. @@ -205,7 +206,7 @@ function add(a, b) { `a` and `b` could be strings, booleans, or anything else. TypeScript can't know from the function body what type they're supposed to be. -So, when you're declaring a named function, their parameters always need annotations in TypeScript. +So, when you're declaring a function, their parameters always need annotations in TypeScript. ### The `any` Type diff --git a/book-content/chapters/05-unions-literals-and-narrowing.md b/book-content/chapters/05-unions-literals-and-narrowing.md index 72faf71..2741002 100644 --- a/book-content/chapters/05-unions-literals-and-narrowing.md +++ b/book-content/chapters/05-unions-literals-and-narrowing.md @@ -603,7 +603,21 @@ function validateUsername(username: string | null): boolean { } ``` -##### Option 5: Extract the check into its own variable +##### Option 5: Check for `null` directly + +Another option is to check for `null` directly: + +```typescript +function validateUsername(username: string | null): boolean { + if (username === null) { + return false; + } + + return username.length > 5; +} +``` + +##### Option 6: Extract the check into its own variable Finally, for readability and reusability purposes you could store the check in its own variable `isUsernameOK`. diff --git a/book-content/chapters/07-mutability.md b/book-content/chapters/07-mutability.md index 2f6f5d1..3484ec6 100644 --- a/book-content/chapters/07-mutability.md +++ b/book-content/chapters/07-mutability.md @@ -137,7 +137,7 @@ TypeScript gives us an error below `albumAttributes` inside of the `updateStatus This is happening because TypeScript has inferred the `status` property as a `string` rather than the specific literal type `"on-sale"`. Similar to with `let`, TypeScript understands that the property could later be reassigned: ```typescript -albumAttributes.status = "new-release"; +albumAttributes.status = "not-valid"; ``` This is true even though the `albumAttributes` object was declared with `const`. We get the error when calling `updateStatus` because `status: string` can't be passed to a function that expects `status: "new-release" | "on-sale" | "staff-pick"`. TypeScript is trying to protect us from potential runtime errors. diff --git a/book-content/chapters/08-classes.md b/book-content/chapters/08-classes.md index 21d995d..d342e38 100644 --- a/book-content/chapters/08-classes.md +++ b/book-content/chapters/08-classes.md @@ -248,7 +248,7 @@ class Album { } ``` -The `#` syntax behaves the same as `private`, but it's a newer feature that's part of the ECMAScript standard. This means that it can be used in JavaScript as well as TypeScript. +The `#` syntax behaves the same as `private`, but it actually comes from JavaScript, not TypeScript. Attempting to access a `#`-prefixed property from outside of the class will result in a syntax error: @@ -263,7 +263,9 @@ const loopFindingJazzRecords = new Album(); console.log(loopFindingJazzRecords.#rating); // SyntaxError ``` -Attempting to cheat by accessing it with a dynamic string will return `undefined` - and still give a TypeScript error. +This would also fail at runtime, too! But TypeScript helps us catch this at compile time. + +Attempting to cheat by accessing it with a dynamic string won't fail at runtime. But it will return `undefined` - and still give a TypeScript error. ```ts twoslash // @errors: 7053 @@ -277,7 +279,7 @@ const loopFindingJazzRecords = new Album(); console.log(loopFindingJazzRecords["#rating"]); // Output: undefined ``` -So, if you want to ensure that a property is truly private, you should use the `#` syntax. +So, if you want to ensure that a property is private at runtime _and_ compile time, you should use the `#` syntax. ## Class Methods @@ -346,7 +348,7 @@ myObj.arrow(); // { location: 'Class' } myObj.method(); // { location: 'Object' } ``` -In the `arrow` method, `this` is bound to the instance of the class where it was defined. In the `method` method, `this` is bound to the object where it was called. +In the `arrow` method, `this` is bound to the instance of the class where it was defined. In the `method` method, `this` is bound to the object where it was called - which is the `myObj` object. This can be a bit of a gotcha when working with classes, whether in JavaScript or TypeScript. diff --git a/book-content/chapters/09-typescript-only-features.md b/book-content/chapters/09-typescript-only-features.md index f27f368..ff5a6da 100644 --- a/book-content/chapters/09-typescript-only-features.md +++ b/book-content/chapters/09-typescript-only-features.md @@ -495,7 +495,7 @@ Imagine ES modules, with `import` and `export`, never existed. In this world, ev This is the world that TypeScript was born into. Module systems like CommonJS (`require`) and ES Modules (`import`, `export`) weren't popular yet. So, namespaces were a crucial way to avoid naming conflicts and organize your code. -But now that ES modules are widely supported, you should use them over namespaces. Namespaces have very little relevance in modern TypeScript code, with some exceptions which we'll explore in our chapter on global scopes. +But now that ES modules are widely supported, you should not use namespaces. Namespaces have very little relevance in modern TypeScript code, with some exceptions which we'll explore in our chapter on global scopes. ## When to Prefer ES vs. TS