I created a wrapper for GetServerSideProps
SSR function to reduce repetition but I have problem with typing it correctly with TypeScript. Here's the wrapper:
type WithSessionType = <T extends {}>(
callback: GetServerSideProps<T>
) => GetServerSideProps<{ session: Session | null } & T>
// v error
const withSession: WithSessionType = (callback) => async (ctx) => {
const session = await getSession(ctx)
const result = await callback?.(ctx)
const props = result && 'props' in result ? result.props : {}
return {
...result,
props: {
session,
...props,
},
}
}
The error:
Type '(ctx: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>) => Promise<{ props: { session: Session | null; }; redirect: Redirect; } | { ...; } | { ...; }>' is not assignable to type 'GetServerSideProps<{ session: Session | null; } & T, ParsedUrlQuery, PreviewData>'.
Type 'Promise<{ props: { session: Session | null; }; redirect: Redirect; } | { props: { session: Session | null; }; notFound: true; } | { props: { session: Session | null; }; }>' is not assignable to type 'Promise<GetServerSidePropsResult<{ session: Session | null; } & T>>'.
Type '{ props: { session: Session | null; }; redirect: Redirect; } | { props: { session: Session | null; }; notFound: true; } | { props: { session: Session | null; }; }' is not assignable to type 'GetServerSidePropsResult<{ session: Session | null; } & T>'.
Type '{ props: { session: Session | null; }; }' is not assignable to type 'GetServerSidePropsResult<{ session: Session | null; } & T>'.
Type '{ props: { session: Session | null; }; }' is not assignable to type '{ props: ({ session: Session | null; } & T) | Promise<{ session: Session | null; } & T>; }'.
Types of property 'props' are incompatible.
Type '{ session: Session | null; }' is not assignable to type '({ session: Session | null; } & T) | Promise<{ session: Session | null; } & T>'.
Type '{ session: Session | null; }' is not assignable to type '{ session: Session | null; } & T'.
Type '{ session: Session | null; }' is not assignable to type 'T'.
'{ session: Session | null; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.ts(2322)
Usecase (that works):
export const getServerSideProps = withSession(async () => {
return {
props: {
custom: 'custom string type',
},
}
})
Here is a computed type of getServerSideProps
:
const getServerSideProps: GetServerSideProps<{
session: Session | null;
} & {
custom: string;
}, ParsedUrlQuery, PreviewData>
It works fine and even InferGetServerSidePropsType
infers types correctly but the mentioned error still occurs.
Any idea how can I make the TypeScript happy here? Also looking forward suggestions and tips regarding this kind of wrapper if you have any.
UPDATE
I found what is the cause but I don't quite understand why is that.. Turns out it treated this statement as always false even though props
can exist on this type.
GetServerSidePropsResult type:
export type GetServerSidePropsResult<P> =
| { props: P | Promise<P> }
| { redirect: Redirect }
| { notFound: true }
Why is only redirect
visible on this type and not props
or notFound
?