From 399c25fbe93a936ab544bb34aa66b75f780f1eb8 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Wed, 10 Jul 2024 21:14:25 +0100 Subject: [PATCH] Small book tweaks --- book-content/chapters/08-classes.md | 6 +----- book-content/chapters/10-deriving-types.md | 21 ++++++++++--------- .../chapters/14-configuring-typescript.md | 8 +++---- book-content/chapters/16-the-utils-folder.md | 6 +++--- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/book-content/chapters/08-classes.md b/book-content/chapters/08-classes.md index fc26f59..21d995d 100644 --- a/book-content/chapters/08-classes.md +++ b/book-content/chapters/08-classes.md @@ -98,7 +98,7 @@ constructor(opts: { title: string; artist: string; releaseYear: number }) { The `this` keyword refers to the instance of the class, and it's used to access the properties and methods of the class. -Now, when we create a new instance of the `Album` class, we can pass an object with the properties we want to set. If we don't provide any values, the default values will be used: +Now, when we create a new instance of the `Album` class, we can pass an object with the properties we want to set. ```typescript const loopFindingJazzRecords = new Album({ @@ -108,10 +108,6 @@ const loopFindingJazzRecords = new Album({ }); console.log(loopFindingJazzRecords.title); // Output: Loop Finding Jazz Records - -const unknownAlbum = new Album(); - -console.log(unknownAlbum.title); // Output: Unknown Album ``` ### Using a Class as a Type diff --git a/book-content/chapters/10-deriving-types.md b/book-content/chapters/10-deriving-types.md index a7af8b0..3bac800 100644 --- a/book-content/chapters/10-deriving-types.md +++ b/book-content/chapters/10-deriving-types.md @@ -520,7 +520,7 @@ Notice there is a lot of duplication here. Both the `FormValues` interface and ` Your task is to modify the `inputs` Record so its keys are derived from the `FormValues` interface. - + ### Exercise 2: Derive a Type from a Value @@ -555,7 +555,7 @@ We want to use the `Environment` type across our application. However, the `conf Your task is to update the `Environment` type so that it is derived from the `configurations` object. - + ### Exercise 3: Accessing Specific Values @@ -587,7 +587,7 @@ type test = Expect>; Your task is to find the proper way to type `Group` so the test passes as expected. - + ### Exercise 4: Unions with Indexed Access Types @@ -617,7 +617,7 @@ type test = Expect< This time, your challenge is to update the `PlannedPrograms` type to use an indexed access type to extract a union of the `ProgramModeMap` values that included "`planned`". - + ### Exercise 5: Extract a Union of All Values @@ -658,7 +658,7 @@ type test = Expect< Using what you've learned so far, your task is to update the `AllPrograms` type to use an indexed access type to create a union of all the values from the `programModeEnumMap` object. - + ### Exercise 6: Create a Union from an `as const` Array @@ -681,6 +681,7 @@ A test has been written to check if an `AllPrograms` type is a union of all the import { Equal, Expect } from "@total-typescript/helpers"; type AllPrograms = unknown; // ---cut--- + type test = Expect< Equal< AllPrograms, @@ -698,7 +699,7 @@ Your task is to determine how to create the `AllPrograms` type in order for the Note that just using `keyof` and `typeof` in an approach similar to the previous exercise's solution won't quite work to solve this one! This is tricky to find - but as a hint: you can pass primitive types to indexed access types. - + ### Solution 1: Reduce Key Repetition @@ -1050,7 +1051,7 @@ In addition to being a bit annoying to write and read, the other problem with th Your task is to use a utility type to fix this problem. - + ### Exercise 8: Typing Based on Return Value @@ -1090,7 +1091,7 @@ type test = Expect< Your task is to update the `User` type so the test passes as expected. - + ### Exercise 9: Unwrapping a Promise @@ -1124,7 +1125,7 @@ Like before, assume that you do not have access to the implementation of the `fe Your task is to update the `User` type so the test passes as expected. - + ### Solution 7: A Single Source of Truth @@ -1340,7 +1341,7 @@ Similarly to `Exclude`, `Extract` works by pattern matching. It will extract any This means that, to reverse our `Extract` example earlier, we can use it to extract all strings from a union: -```typescript +```ts twoslash type Example = "a" | "b" | 1 | 2 | true | false; type Strings = Extract; diff --git a/book-content/chapters/14-configuring-typescript.md b/book-content/chapters/14-configuring-typescript.md index 513e418..c79f612 100644 --- a/book-content/chapters/14-configuring-typescript.md +++ b/book-content/chapters/14-configuring-typescript.md @@ -141,7 +141,7 @@ This code will error in your target environment, because `target` won't transfor If you're not sure what to specify for `target`, keep it up to date with the version you have specified in `lib`. -### `esModuleInterop` +### `esModuleInterop` `esModuleInterop` is an old flag, released in 2018. It helps with interoperability between CommonJS and ES modules. At the time, TypeScript had deviated slightly from commonly-used tools like Babel in how it handled wildcard imports and default exports. `esModuleInterop` brought TypeScript in line with these tools. @@ -164,7 +164,7 @@ declare const enum AlbumFormat { Digital, } -const largestPhysicalSize = AlbumFormat.Vinyl; // red squiggly line under AlbumFormat when isolatedModules is enabled +const largestPhysicalSize = AlbumFormat.Vinyl; ``` Recall that the `declare` keyword will place `const enum` in an ambient context, which means that it would be erased at runtime. @@ -241,7 +241,7 @@ const nonExistentTrack = egoMirror.tracks[3]; console.log(nonExistentTrack.toUpperCase()); // no error in VS Code // However, running the code results in a runtime error: -TypeError: Cannot read property 'toUpperCase' of undefined +// TypeError: Cannot read property 'toUpperCase' of undefined ``` 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`: @@ -286,7 +286,7 @@ const egoMirror: VinylSingle = { const ego = egoMirror.tracks[0]; // ---cut--- -console.log(ego.toUpperCase()); // red squiggly line under ego +console.log(ego.toUpperCase()); ``` This means that we have to handle the possibility of `undefined` values when accessing array or object indices. diff --git a/book-content/chapters/16-the-utils-folder.md b/book-content/chapters/16-the-utils-folder.md index 45dcbe2..fdc2e0d 100644 --- a/book-content/chapters/16-the-utils-folder.md +++ b/book-content/chapters/16-the-utils-folder.md @@ -51,7 +51,7 @@ const identity = (arg: T): T => arg; We can even declare a generic function as a type: ```typescript -type Identity = (arg: T) => void; +type Identity = (arg: T) => T; const identity: Identity = (arg) => arg; ``` @@ -68,12 +68,12 @@ It's very important not to confuse the syntax for a generic type with the syntax ```typescript // Type alias for a generic function -type Identity = (arg: T) => void; +type Identity = (arg: T) => T; // ^^^ // Type parameter belongs to the function // Generic type -type Identity = (arg: T) => void; +type Identity = (arg: T) => T; // ^^^ // Type parameter belongs to the type ```