Type Checking your Next JS App

Next JS has proven to be an awesome React framework that many developers now use. Combining this technology with TypeScript allows for a more robust developer experience. I'll show how to add TypeScript to your Next.js project and how to use it to add type-checking to your app.

Setting Up the App

The best way to get started with Next JS and TypeScript is by using the ts flag when creating the project.

npx create-next-app nextjs-typescript-demo --ts

Using Next JS's types

Pages and Server Side Rendering

When you open up the index.tsx file, one of the things that has changed is that the pages are typed using the NextPage type that is imported from Next JS. You should do this whenever you create a new page.

If you want to do server side rendering or static generation, Next JS has built in types for those as well:

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from "next";

export const getStaticProps: GetStaticProps = async (context) => {
  return {
    props: {},
  };
};

export const getStaticPaths: GetStaticPaths = async () => {
  return {
    paths: [
      {
        params: {},
      },
    ],
    fallback: true,
  };
};

export const getServerSideProps: GetServerSideProps = async (context) => {
  return {
    props: {},
  };
};

Click here if you want to learn about how to use getInitalProps with TypeScript.

For the props or paths being returned, you can use angle brackets in the NextPage type (because the type is generic) to specify the prop/path types.

interface Props {
  // ...
}

const Home: NextPage<Props> = () => {
  return <div>Hello World</div>;
};

Components

To build components that will be used inside of your app, you should use the NextComponent type. By default the component will be typed as NextComponent<NextPageContext, {}, {}> The third argument can be extended to type check your props:

import { NextComponentType, NextPageContext } from "next";

interface Props {
  // ...
}

const Dummy: NextComponentType<NextPageContext, {}, Props> = () => {
  return <div></div>;
};

API Routes

You can also type check your API routes by using Next.js's built in types.

import type { NextApiRequest, NextApiResponse } from "next";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ response: "Type checked API response" });
}

You can type the repsonse data and pass it into NextApiResponse:

type Data = {
  response: string;
};

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  res.status(200).json({ response: "Type checked API response" });
}

Custom App and Next Config

The _app.js and next.config.js files are also typed using the built in types. The _app.js is typed using the AppProps type and the next.config.js is typed using the NextConfig type.

Example: Fetching an API

Lets fetch the JSON Placeholder API to get some posts and test our type checking skills. First in the index.tsx file, we will need to use the getStaticProps (because the API data doesnt't change) to get the data.

export const getStaticProps: GetStaticProps = async () => {};

Now we will need query the API and return the results:

export const getStaticProps: GetStaticProps = async () => {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts");
  const posts = await res.json();

  return {
    props: {
      posts,
    },
  };
};

Now we have a problem. When you hover over the posts variable (in VSCode), it will say that the type is any. That is not what we want; the purpose of TypeScript is to make sure everything is statically typed.

One way to type the API results is go to thw API documentation and figure it out from there. The better way is to fetch the API and paste the results into Quicktype. Quicktype will automatically generate types and interfaces for the data. I have already done that, and the API response will be in the following format:

export default interface PostType {
  userId: number;
  id: number;
  title: string;
  body: string;
}

Usually, we would create a types folder, create a new file (maybe called PostType.ts) and export the interface.

Now we will receive an array of posts. We can now type check the posts variable:

const posts: PostType[] = await res.json();

Now to receive the posts in the actual page, we need to extend the NextPage type to include our props. Then we can use the posts.

type HomeProps = {
  posts: PostType[];
};

const Home: NextPage<HomeProps> = ({ posts }) => {};

Now we can map through the posts and display them on the page using a Post component.

posts.map((post) => (
  <Post
    key={post.id}
    userId={post.userId}
    id={post.id}
    title={post.title}
    body={post.body}
  />
));

Now when we create the Post component, we have to keep in mind the props we have to pass in. You can use the PostType interface for the props, but I will create a separate type for the Post props. Then we can use the NextComponentType type to type check the props.

type PostProps = {
  userId: number;
  id: number;
  title: string;
  body: string;
};

const Post: NextComponentType<NextPageContext, {}, PostProps> = ({
  userId,
  id,
  title,
  body,
}) => {};

Now we can just display all the information:

<div>
  <p>User ID: {userId}</p>
  <p>ID: {id}</p>
  <p>Title: {title}</p>
  <p>Body: {body}</p>
  <br />
</div>

Conclusion

Using TypeScript in any app allows for a more robust developer experience. Next JS makes no exception. i hope you learned a lot from this tutorial!

Here is the code for this tutorial.

Signing off 👋

Please email me if I have any typos in the guide or if something doesn't look right.