As developers, we're always seeking ways to enhance our workflow and minimize errors in our applications. This explains TypeScript's explosion in popularity, offering benefits such as type checking and tooling.
But for all of TypeScript's benefits, it's not without some pain points. Integrating TypeScript when consuming APIs can be repetitive when it comes to maintaining type definitions. That’s where pre-generated types and codegen can be leveraged to reduce the manual work of keeping API types in sync with queries.
In this article, we'll explore how to manually incorporate types with the Storefront API, look at a pre-generated approach and then dive into how the new GraphQL Codegen feature in Hydrogen changes the game.
A primer on TypeScript
TypeScript is a superset of JavaScript that brings type checking and other advanced features to the language.
It’s become increasingly popular among developers due to its ability to catch errors early, ensure data consistency, and provide a better development experience through features like autocompletion. Many Shopify developers generate their apps and Hydrogen projects in TypeScript flavors to take advantage of these robust features.
GraphQL API Example
When working with a GraphQL API, defining accurate types ensures a smooth development experience and minimizes runtime errors. Here's an example of defining types when fetching data from the Storefront API:In the example above, I've defined a Product
type and passed it along to the query function. The static typing provided by TypeScript helps ensure my code is consistent and predictable, and provides handy tools like autocomplete. When interacting with the product
object, my IDE now knows there are three possible properties I could be working with:
It also lets me know when I mess up by highlighting when a property I'm trying to use doesn't exist:
However, the process of manually maintaining these types in sync with our GraphQL queries can be time-consuming and error-prone. Want to fetch an additional field? Don't forget to find and update the types!
Pre-generated types
The above process can be streamlined by using pre-generated types - for the Storefront API, there's the storefront-api-types utility. With a simple import, all of the Storefront API types are available for use:
import type { Product } from '@shopify/hydrogen/storefront-api-types';
const product = await storefront.query(FEATURED_PRODUCT_QUERY);
It's refreshing not having to manually construct the types, but while super convenient, it can feel like overkill having every field defined - autocomplete gives me fields I’m not even querying for:
GraphQL Codegen: Automatically Generated TypeScript Types
Enter GraphQL Codegen: a tool that automatically generates types based on your queries like magic! This means you no longer have to manually keep types in sync, or rely on superfluous type definitions.
It's available to use in Hydrogen today with the --codegen-unstable
flag.
npm run dev -- --codegen-unstable
Codegen automatically generates types for all of the queries in my project and stores them in a storefrontapi.generated.d.ts
file. The Storefront client (provided by Hydrogen) automatically reads these types and with that, they're available without any setup.
The power of components
But the real power of Codegen is when you link the types to a component. Here I’m importing the generated type - it’s called FeatureProductQuery
because my query is called featuredProduct
(every time you create a query, codegen will create a type of the same name).
Now if I try to render the collection description (not part of the query), TypeScript alerts me that the property doesn’t exist.
All I need to do is add description to the query - the types are updated and we’re in business!
Codegen tips
- Be sure to name your operations, and keep those names unique. Codegen will use the operation name to generate a type of the same name.
- You can configure the generator by creating a codegen.ts file in the root of your project.
- If you're using embedded expressions to include variables in a query, cast the query
as const
. This prevents TypeScript from inferring a generic "string" type for the query.
Conclusion
While TypeScript provides numerous benefits, maintaining types while working with GraphQL APIs can introduce friction. GraphQL Codegen overcomes these challenges by ensuring your types are automatically generated based on your schema, resulting in a more efficient and enjoyable development process.
I hope you lean on the power of GraphQL Codegen to speed up your development workflow!