How to Type Data from GraphQL With TypeScript Generics

Although the custom server fetch() function we've established in the last lesson works, the data being returned isn't appropriately typed. In this lesson, we'll take advantage of TypeScript generics to ensure we get queried data from our server fetch() function with the appropriate type.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.

Thumbnail for the \newline course TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL
  • [00:00 - 00:11] Though our simple server function works, we still have an issue where data being retrieved from the server fetch function doesn't have a type associated with it. To solve this issue, we'll take advantage of TypeScript generics.

    [00:12 - 00:23] We've seen how generics worked both when we were building the server application, as well as when we surveyed the function component interface. But we haven't had a chance to create our own generic abstraction.

    [00:24 - 00:36] We want the server fetch function to return the data from the request, but in addition, this data should also be typed. We also want the fetch function to work for any data object with its own unique type.

    [00:37 - 00:52] Where do we know what the type of data looks like? The server fetch function has no idea what the type of data could be, however in the component where the fetch function is being called, we have an idea of the data we're expecting because we're defining the query we expect.

    [00:53 - 01:19] For listings in particular, we expect an array of listings where ID, title, image, address to be strings, and the price, number of guests, number of beds, number of baths , we'll add that one in since we haven't yet, and rating fields to be numbers. If we have an idea of the shape of the data from the request, we essentially want to pass that shape of data into the server function, and we can achieve this with gener ics.

    [01:20 - 01:42] So first and foremost, in the server fetch function, we'll use angled brackets and declare that this function can accept a type variable denoted by t data to represent that this is a type data. We'll specify a default type parameter of any to say if the type of data isn't provided, we'll just set it as any.

    [01:43 - 01:58] By having access to this type variable, we can now set the return type of the function to the type we expect. The response.json function returns a value of promise, but it doesn't give us the option of passing in a type variable.

    [01:59 - 02:09] When our function is successful, we're confident of how the data is going to be returned. So this is where we can type assert the return value to what we expect.

    [02:10 - 02:31] So for now, we'll type assert the return statement as a promise when resolved would be an object that has a data field and this data field will be of type t data. Type assertions are a capability where we can override the types that Type Script either infers or analyzes.

    [02:32 - 02:42] It's a way of telling TypeScript, "Hey, trust me, I know what I'm doing." There's two ways of type asserting, either using the as syntax or using the angled brackets syntax.

    [02:43 - 02:55] The ESLint setup prefers the as syntax and so do we. Now, type assertions should be used sparingly because it's easy to type assert variables without specifying the properties that are needed in the type.

    [02:56 - 03:11] In the vast majority of time, we assign types normally, only in cases we think we know better than a compiler do we type assert. Now the data being returned can be typed as the type value being passed into the function.

    [03:12 - 03:21] Let's see how this would work for our listings component. In the listings component, we'll specify the interface of the data we expect to be returned from the server.

    [03:22 - 03:35] We'll create this interface type in a types file within the listings folder. We'll first create an interface called listing that describes the shape of a single listing object.

    [03:36 - 04:07] We'll then export an interface labeled listings data that represents the shape of the data field returned from our API. When we query listings, we can see that data contains a listings field which is an array of listing items.

    [04:08 - 04:27] So we'll specify the listings data interface as so. We'll import the listings data type in the listings components and pass it down as a type variable for the server fetch function.

    [04:28 - 04:35] Now the data being returned is appropriately typed. If we attempt to access the listings field within data, we should be able to do so.

    [04:36 - 04:42] If we want to access some other property that didn't exist, TypeScript will now throw an error. Amazing.

    [04:43 - 05:14] Our app still behaves the same since we haven't made any functional changes. [ Silence ]