6

The current code I have is below, which follows the tutorials for Next.js per page getLayout (see TypeScript section) and NextAuth with TypeScript (or should I say, tries to follow...):

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react";
import { Session } from "next-auth";
import Header from "components/Header";
import { ReactElement, ReactNode } from "react";
import { NextPage } from "next";

type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode;
};

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout;
};

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout || ((page: any) => page);

  return getLayout(
    <SessionProvider session={pageProps.session}>
      <Header />
      <Component {...pageProps} />
    </SessionProvider>
  );
}

export default MyApp;

I keep getting the error Property 'session' does not exist on type '{}'.ts on pageProps.session. What do I need to change the TypeScript to, to make this work?

juliomalves
  • 42,130
  • 20
  • 150
  • 146
Dimitri Borgers
  • 328
  • 4
  • 15

3 Answers3

8

You can add a generics type to AppPropsWithLayout, then use it in the MyApp's props type and pass the right type for session. Note that this will only work for Next.js 12.3 onwards, as support to type pageProps through AppProps was only added in https://github.com/vercel/next.js/pull/38867.

import type { Session } from "next-auth";

// No changes to this type
type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
    getLayout?: (page: ReactElement) => ReactNode;
};

// Add generic type
type AppPropsWithLayout<P> = AppProps<P> & { 
    Component: NextPageWithLayout<P>; 
}; 

// Pass `{ session: Session; }` type as generic
function MyApp({ Component, pageProps }: AppPropsWithLayout<{ session: Session; }>) {
    const getLayout = Component.getLayout || ((page: any) => page);

    return 
        <SessionProvider session={pageProps.session}>
            {getLayout(
                <>
                    <Header />
                    <Component {...pageProps} />
                </>
             )}
        </SessionProvider>
    );
}

As an aside, I'd avoid wrapping getLayout around the session provider as it may cause issues with the context.

juliomalves
  • 42,130
  • 20
  • 150
  • 146
1

Similar to juliomalves' answer above, I did it this way

export type NextPageWithLayout = NextPage & {
    getLayout?: (page: ReactElement) => ReactNode
};

type AppPropsWithLayout<P> = AppProps<P> & {
  Component: NextPageWithLayout;
};

const MyApp = ({
  Component,
  pageProps: { session, ...pageProps },
}: AppPropsWithLayout<{ session: Session | null; }>) => {
    const getLayout = Component.getLayout ?? ((page) => page)
    return (
        <SessionProvider session={session}>
            {getLayout(<Component {...pageProps} />)}
        </SessionProvider>
    )
}
myNameCoad
  • 2,583
  • 2
  • 12
  • 15
0

I ran into this a couple days ago, I'll try to find the link but the solution was:

function MyApp({ Component, pageProps, }: AppProps<{ session: Session; }>) {

  return (
    <SessionProvider session={pageProps.session}>

from one of the answers at: (NextAuth) Type error: Property 'session' does not exist on type '{}'

Sujio
  • 357
  • 1
  • 2
  • 13
  • also just curious what tutorial are you following? what is ` type NextPageWithLayout

    = NextPage

    & { getLayout?: (page: ReactElement) => ReactNode; }; `?

    – Sujio Oct 04 '22 at 03:13
  • Made some edits to include the links. The solution you have here is just for NextAuth working with NextJS (same link I used!), but doesn't work with getLayout – Dimitri Borgers Oct 04 '22 at 15:49