Up to this point in our app, the only help we are getting from typescript is from SvelteKit's built in types. But these types don't infer our data structure so we need to add types using JSDoc and zod.
One of the benefits of zod is that it can be used for schema validation in javascript by using the built in parse helper function. You can also infer type definitions from zod schemas using the infer helper.
We can then use those types that we infer from zod schemas in our JSDoc comments to get type safety where we need.
If you want a deeper dive into typescript and zod, Matt Pocock has created to great free resources at Total Typescript
Instructor: [0:00] We're getting our data from the CMS, but the only help we're getting from TypeScript is from the types built into SvelteKit. If we look at our data, we see that it has the post, which is good, but it doesn't have any typing to it.
[0:13] Let's come into our sanity.js file. If we look at this config, let's do /**, and that completes for you. When you click Enter, let's put type. Then, the type goes here but our type is actually going to be an object, so we'll give it another set of brackets. Then we'll say Project ID, which is a string. You'll see, we're already getting help from TypeScript.
[0:40] JSDoc comments look at what's directly below them. It's saying that this config only has a Project ID type, so it doesn't know what these other types are. Let's go ahead and finish typing that, and say Dataset, which is a string, and API Version, which is a string.
[0:59] It's cool, we have this inline object that's typing our config. Let's type our getAllPost function. We have our Sanity Client, which it's being set to Sanity Client based off of this inferred type from Create Client.
[1:17] If we want to be explicit with that, we can come in and import Sanity Client, and then we can give our Sanity Client function the return type and just say, Sanity Client.
[1:35] Next, we have our AllPosts, which currently is just an any type, and say @type, and we'll give it another object, and there will be a title, which is a string, and a slug, which is a string, which is great. This works fine, and it's typing it right.
[1:53] We are going to get an error on our page because this is supposed to be an array. We can fix that if we come back into our sanity.js and just give it the brackets. That fixed it for us. We can do this a different way by coming into our lib and creating a new file called types.d.ts. This is a declaration file for our types.
[2:18] First, we want to instal Zod, so npm zod, and then import Zod. The nice thing about Zod is you can create schemas that can be used for both parsing data, to validate your data, and infer types from. First, we can say, export const AllPostsSchema, which will be z.array, which is an object that has the title property, which is a string, and the slug property, which is a string.
[2:59] Let's save that. Then, in our sanity.js file, let's just import that schema, import AllPostsSchema from types.Then, in our getAllPosts function, let's get rid of this type, and let's use the AllPostsSchema that we just imported and parse all the posts.
[3:28] If we save that and we go back to our page, we'll see that we're still getting the type safety that we want. That's great. We can do it that way. We're still getting this any type. We can come back into our types, and here we can infer our AllPosts type from our AllPostsSchema. Zod provides a helper for that.
[3:55] We can say, export type AllPosts, and say, z.infer<typeof AllPostsSchema>. Instead of importing this at the top, because it is a type, we can't import types and use them, but in JSDoc comments, we can actually import them inline. We can just come here and say, @type, which is import, and we're going to import it from our types.
[4:28] Then, we're going to access the AllPosts type. Then, if we look at our AllPosts, we see that it is the type that we are expecting. Now we also want to do this for our Post type. We can go ahead and initialize our comment and say it's @type. We're going to make it the import from our types, and we're going to have a Post type.
[4:54] Currently we don't have that, so we'll get an error. We can go create that type. Let's create our schema first. Then, we also know we want our type from it, we save that, our error here should go away. Now our Post is the correct type.
[5:10] Now let's also import our Posts schema and parse our posts. Now, let's run our server. We're actually getting an error. We see that this error is from Zod. This is our validation error. It's saying that it is expecting an object and got an array on our get post by slug function.
[5:36] If we remember in our page.server.js for our single posts, we were getting an array back and we had to index in and get the post off of that array. If we remove that, then go back to our Sanity JS and add that on the post, it's going to give us an error because our post isn't an array. It's an object.
[5:59] We can just add the array bracket there. If we save that, we're back to getting our data and now we have types as well. The last thing we need to do is change this type. Import types and we're just going to access the Sanity config is what we will call it. And so, then let's create that type and come back.
[6:24] Everything is working as we expected. As an extra step, you could work on adding return types to the get all posts function and the get post by slug function. You'll probably need to use the promise helper from TypeScript and the import syntax as well.
[6:40] If you want additional help with TypeScript, Matt Pocock has added great learning resources at totaltypescript.com. He's got a few great beginner resources that are free for beginners TypeScript and Zod. In this lesson, we learned how to add js.comments and how to create Zod schemas and infer types from those schemas.