diff --git a/book-content/chapters/16-the-utils-folder.md b/book-content/chapters/16-the-utils-folder.md index 94b6fa7..2656213 100644 --- a/book-content/chapters/16-the-utils-folder.md +++ b/book-content/chapters/16-the-utils-folder.md @@ -302,102 +302,9 @@ Note how clever TypeScript is being here. Even though we didn't specify a return -### Combining Generic Types and Functions +### Type Safe vs Type Faith -Generic functions are useful on their own, but they really start to shine when combined with generic types. Let's look at a real-world example of how flexible this combination can be. - -Here we have a regular, non-generic function that fetches an `Album`'s data from an API: - -```typescript -type Album = { - id: number; - title: string; - artist: string; - year: number; -}; - -async function fetchAlbum(id: number): Promise { - const response = await fetch(`https://api.example.com/albums/${id}`); - return response.json(); -} -``` - -If we wanted to fetch a `Song` or a `Playlist`, we would need to create similar functions with different types: - -```typescript -type Song = { - id: number; - title: string; - duration: number; -}; - -type Playlist = { - id: number; - name: string; - songs: Song[]; -}; - -async function fetchSong(id: number): Promise { - const response = await fetch(`https://api.example.com/songs/${id}`); - return response.json(); -} - -async function fetchPlaylist(id: number): Promise { - const response = await fetch(`https://api.example.com/playlists/${id}`); - return response.json(); -} -``` - -These functions are almost identical, with the only difference being the type of data being fetched and the URL endpoint. This is a perfect opportunity to bring in generic types and functions. - -#### Refactoring to be Generic - -To start, we'll make a generic `ApiResponse` type that represents the structure of the API response. This type will take a type parameter `T` to represent the type of data being returned, as well as a `status` and `message` property for additional metadata: - -```typescript -type ApiResponse = { - data: T; - status: number; - message: string; -}; -``` - -This `ApiResponse` type will support the `Album`, `Song`, and `Playlist` types, and ensure that all API responses have a consistent structure. - -Next, we'll create a generic function that can fetch any type of data from the API. The `fetchData` function will take in a type parameter `T` that corresponds to `Album`, `Song`, or `Playlist`, along with an `endpoint` parameter that specifies the API endpoint. The return type will be a `Promise` that resolves to an `ApiResponse` object for the same type `T` being passed in: - -```typescript -async function fetchData(endpoint: string): Promise> { - const response = await fetch(`https://api.example.com/${endpoint}`); - const data = await response.json(); - return { - data, - status: response.status, - message: response.statusText, - }; -} -``` - -Now we can use the generic `fetchData` function with any of our types by specifying the type argument and the endpoint: - -```typescript -async function getAlbum(id: number): Promise { - const response = await fetchData(`albums/${id}`); - return response.data; -} - -async function getSong(id: number): Promise { - const response = await fetchData(`songs/${id}`); - return response.data; -} - -async function getPlaylist(id: number): Promise { - const response = await fetchData(`playlists/${id}`); - return response.data; -} -``` - -Each function will return the fetched data of the specified type, and the `ApiResponse` type ensures that the response has a consistent structure. + ## Type Predicates