How to type nextjs page's props in one line

TL;DR;

Use the following line to automatically type your nextjs page props with the returned type of getServerSideProps or getStaticProps

type Props = Awaited<ReturnType<typeof getServerSideProps>>['props']

When working on a nextjs page that receives props from a data fetching method, normally i would type the response of the method and the props the page component receives individually, meaning i would duplicate the type definition, like so

type Props = {
    users: User[]
}

export default function TestFetchers({ users }: Props) {
    return (
        <ul>
            {users.map((user) => (
                <li key={user.name}>{user.name}</li>
            ))}
        </ul>
    )
}

type User = { name: string }

export async function getServerSideProps() {
    const users: User[] = getUsers()

    return {
        props: {
            users,
        },
    }
}

Nothing terribly wrong with that but when you need to add more props, you need to manually modify the Props type, which to me seems like an unnecessary step. After all, we know what getServerSideProps is returning.

Well, you can achieve that with the following line

type Props = Awaited<ReturnType<typeof getServerSideProps>>['props']

Let's break it down

Awaited is one of the typescript utility types and it represents the returned type of a async function. ReturnType is another utility type that, as the name indicates, creates a type from the return type of a function.

Combining both we can create a type that represents the return type of the promise returned by our method getServerSideProps. As the return type of getServerSideProps represents more than just the props key, we just pick that one by using the square brackets notation.

So, that's it. An elegant combination of the utility types allow you to have type-safe props in your page component without having to manually define them. Pretty neat!

Full example

type Props = Awaited<ReturnType<typeof getServerSideProps>>['props']

export default function TestFetchers({ users }: Props) {
    return (
        <ul>
            {users.map((user) => (
                <li key={user.name}>{user.name}</li>
            ))}
        </ul>
    )
}

type User = { name: string }

export async function getServerSideProps() {
    const users: User[] = getUsers()

    return {
        props: {
            users,
        },
    }
}