Use Keystatic-Generated Types In The Front End

Share this video with your friends

Social Share Links

Send Tweet
Published a year ago
Updated 2 months ago

In this video, you'll use Keystatic's Entry type to avoid re-creating types for your frontend components.

An added benefit of doing this is that if the Keystatic schema changes, your types will be updated accordingly.

[00:00] In our author's page, we're currently rendering all the showcase blocks in line. So we have the link block and then we have the YouTube video block. And there's nothing wrong with doing that here. But let's say that for some reason, we wanted to move some of this markup to different files, to component files. That might be useful if you have a lot more blocks and you wanna break down each [00:19] block into its own component or say you wanted to use the showcase on another page, that would be a good idea to have this code living in a reusable component. So what we're going to do is take these different blocks and instead of having that in the individual author page, we're going to create a new component folder and have the files living in there. So let's create a [00:39] first component file, showcase dash link dot tsx, and I'll basically copy what is inside this link discriminant, so the anchor tag, and create a component out of this export function showcase link, which will return our anchor tag. Obviously, before this works, it's going [00:59] to need to receive some props. It needs a URL and a label. So let's accept these here and then we can get rid of item dot value in both instances. Now in our author's page, let's get rid of that, and instead, we're going to import the showcase link component we've just created and pass the URL and [01:19] the label. But let's not get confused by Copilot. This is item dot value dot urlitem.value.label. And if we check an author page, this still works, everything shows properly, but by moving our showcase link in its own component, we've lost a good amount of type safety. For example, as the [01:39] URL, I could pass a number, 34, and as a label, I could have an object with the Foo bar key value pair. And you can see that nothing is telling me I am doing anything wrong because URL and label can be any. That's a problem because our front end is now broken because we're passing data that it doesn't know what to do with. And so [01:58] to guard against that, we'd want to have some types inside our component here. And, yeah, sure. We could create a type showcase link props, which has a URL and a label both set as strings, and then mark our showcase link component as showcase link props. And by doing so, now we will be told, hey. You shouldn't pass a number. This is [02:18] expecting a string. And here, do not pass an object with a foo property. It also wants a string. And here, if we're going back, everything would be TypeScript happy and the front end would be front end happy. But that's a bit of a bummer to have to manually create these props to mirror key static showcase blocks, so in this case, for the link, [02:38] but we'll also have to do the same for the YouTube video and any other blocks that you may have. And so we don't want to do this. Okay. So instead of manually recreating types to mirror what key static does, we're going to use something that key static's reader export for us, the entry type. In the showcase link component, I'm going to import the entry [02:58] type from key static core reader. And now watch this. We're going to do a bit of TypeScript gymnastic. And you don't have to do this, but I'll break it down in 2 layers here so it's a bit easier to understand. Let's say we wanted to have the type for an author entry. Type author entry equals entry, bear with me, type of, and we're [03:18] going to pass the key static config. And here in square brackets, I can reach the different property of the key static config. In our case, we want the collections and then we want the authors. And by doing this, I now have the complex entry type of each author entry. And you can see here, [03:38] it has a name, an avatar, and then a showcase with the different discriminant for link and YouTube video ID. Here, we're only concerned by the showcase link. So instead of an author entry, let's get showcase. I can drill down inside my entry and get the showcase. And so now our showcase type [03:58] is only the showcase, which is either a discriminant of link with the value object or a discriminant of YouTube video ID with a string. And it's an array of these because it's a repeatable field. And so this is the tricky part and that's also why I wanted to break it down in 2 layers. We're going to try to narrow down our [04:18] type to only the link discriminant for this component. So I'm going to delete this manually created showcase link props object and try to create it from our showcase here. What we want to do here is extract the link discriminant, and so I will use typescript's extract. And what we [04:38] want to extract from is the showcase. And because it's an array, we want just one index of this and I can pass here number to get one index of this array and extract expect a second argument, which is the condition we want to extract on. And here, we [04:58] want to filter out based on the discriminant and only keep the one where the discriminant is link. This is still not right, but let's take a look at what we have. We have now narrowed down our showcase link props to only an object of the link discriminant with the value. And so what we're really [05:18] interested in here is this value object with the URL and label. So at the end of this, I can drill down to the value property. I think we've done it. Our showcase link props is now a URL and label strings just like we did manually, but we're now getting these data from key [05:37] static. And if the key static config changes, if our schema changes for the showcases, our showcase link props type will also change accordingly. And now once again, if instead of passing a string, I pass a number, it's going to immediately yell at me and say that number is not assignable to a type string. So let's go back to item.value.url. [05:59] Let's rapidly repeat the procedure for the video block type. In components, I'll have another file called showcase YouTube video dot tsx. It'll export a function called showcase YouTube video that returns whatever was returned [06:19] inside a condition here. So I'll copy that and paste it here. And we want our showcase YouTube video component to receive a, let's call it, video ID, which we can pass here. So let's delete this. Instead, use our showcase YouTube video component and pass the [06:39] item that value as the video ID prop, and it still works. Once again, I could have here something different like an empty array and our video would now be broken without anything telling us what's wrong because video ID is any. We're gonna work out the correct type from keystatics entry. [06:59] Type showcase YouTube video props. Let's try to do it in one go this time. So first, let's get our showcase entry type of keystatic config, square brackets, collections, square brackets, authors, and then reach out for the [07:19] showcase. And from there, we want to extract from that showcase the items where the discriminant is YouTube video ID. And finally, we wanna get the value. Did I do it right? Let's check what we've [07:39] got. Nope. I did not. So let's have a look. Showcase here for video ID. Okay. So it is YouTube video ID in camel case. So let's replace that. And I'm hoping that this showcase YouTube video props is a string. Nope. Still not. Uh-huh. Yeah. I know what's [07:59] wrong. Remember that this showcase is actually an array and so we want to grab only one of them by passing number here. And so it turns out it wasn't a terrible idea to break it down in 2 layers because it's quite tricky to work it out in one go. It's also not necessarily the most readable type here, but we should [08:18] now have a string. Yes, we do. So I've made the decision to name that prop video ID. So the exact type that we're looking for is that object with video ID as the key and this crazy extraction as the value. And so now I should be able to define this as showcase [08:38] YouTube video props, which really is an object with a video ID set to a string. And now when we use our showcase YouTube video component, we should have more useful information if we pass something wrong like an empty object. It tells us that this is not looking like a string, which is what is expected for the [08:58] video ID prop. So one more time, let's pass item dot value, and our showcase works just like before but we were able to bring types generated from KeyStatic into our front end components.

egghead
egghead
~ 9 minutes ago

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today