JWJames Wallis
Cover for Using getStaticProps and getStaticPaths with TypeScript - Next.js

Using getStaticProps and getStaticPaths with TypeScript - Next.js

24th March 2021

My personal website is built on Next.js and uses both the getStaticProps and getStaticPaths functions to dynamically generate the /blog/ and /portfolio/ pages at build time. While updating both methods to use their proper TypeScript types, following the documentation, I ran into an error when reading the parameter that I was passing from getStaticPaths into getStaticProps.

The error that appeared was:

Property 'slug' does not exist on type 'ParsedUrlQuery | undefined'

After doing some research and finding a discussion on the Next.js GitHub regarding this issue, I recognised it was a gap in their documentation. It explains how to add the type to getStaticProps when used on its own but it doesn't demonstrate how to access the property you've declared in getStaticPaths.


Background

getStaticProps and getStaticPaths are two methods that can be used for data fetching in Next.js. Briefly speaking getStaticProps lets you fetch data at build time and getStaticPaths enables you to specify dynamic routes to pre-render pages based on data.

For more information on these functions, read my post on different ways to fetch data in Next.js.


The error

Using the example code below I will demonstrate the TypeScript error and advise you on how to fix it. I'm using the variable name slug to create the dynamic routes, but you could use anything - another common name is id.

import { GetStaticPaths, GetStaticProps } from 'next'
import { ParsedUrlQuery } from 'querystring'

export const getStaticPaths: GetStaticPaths = async () => {
    const arr: string[] = ['slug1', 'slug2']
    const paths = arr.map((slug) => {
        return {
            params: { slug },
        }
    })
    return { paths }
}

export const getStaticProps: GetStaticProps = async (context) => {
    // This is where the error occurs
    const { slug } = context.params // Property 'slug' does not exist on type 'ParsedUrlQuery | undefined'
    const props = fetch(`/api/${slug}`)
    return { props }
}

Note the first line of the getStaticProps. Here we are attempting to access the slug variable that was created in getStaticPaths and returned inside the params object. This is the line that causes the error as context.params has the type ParsedUrlQuery | undefined and slug does not exist in ParsedUrlQuery.

const { slug } = context.params

The fix

Fortunately, fixing the issue is as simple as creating an interface that extends ParsedUrlQuery and contains a slug property.

interface IParams extends ParsedUrlQuery {
    slug: string
}

Once we've added that to the file, we need to assert that context.params is of type IParams. This is done like so:

const { slug } = context.params as IParams

It's as simple as that! Just adding the IParams interface makes the TypeScript error disappear.

Updated example code:

import { GetStaticPaths, GetStaticProps } from 'next'
import { ParsedUrlQuery } from 'querystring'

interface IParams extends ParsedUrlQuery {
    slug: string
}

export const getStaticPaths: GetStaticPaths = async () => {
    const arr: string[] = ['slug1', 'slug2']
    const paths = arr.map((slug) => {
        return {
            params: { slug },
        }
    })
    return { paths }
}

export const getStaticProps: GetStaticProps = async (context) => {
    const { slug } = context.params as IParams // no longer causes error
    const props = fetch(`/api/${slug}`)
    return { props }
}

Round up

If this post has helped you use Next.js together with TypeScript, react or let me know in the comments!

Thanks for reading!

Sources:

React, comment and follow on