I'm currently in the process of refactoring this code snippet to allow for the reuse of the same middleware logic on multiple pages in a type-safe manner. However, I am encountering difficulties when trying to write a typesafe recursive type that can cater to the specific use case at hand.
Here is the working original code:
import { NextPage, GetServerSidePropsContext } from 'next';
// new InferGetServerSidePropsType fix, waiting for merge to stable
type InferGetServerSidePropsType<T extends (args: any) => any> = Awaited<
Extract<Awaited<ReturnType<T>>, { props: any }>
>;
const getServerSideProps = async (context: GetServerSidePropsContext) =>
(async (context, props) => {
const token = 'token';
if (Math.random() > 0.5)
return {
notFound: true,
};
return (async (context, props) => {
if (context.locale === 'en')
return {
redirect: {
destination: '/en',
permanent: true,
},
};
const permissions = [1, 2, 3];
return (async (context, props) => {
const data = 'data';
return { props: { ...props, data } };
})(context, { ...props, permissions });
})(context, { ...props, token });
})(context, {});
const MyPage: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (props) => {
const { token, permissions, data } = props; // types are infered correctly!
return null;
};
During my initial attempt at defining a recursive intersection between middlewares, I ended up with the following flawed code:
const withToken: GSSPMiddleware<{ token: string }> = (next) => async (context, props) => {
if (Math.random() > 0.5)
return {
notFound: true,
};
const token = 'token';
return next(context, { ...props, token });
};
const withPermissions: GSSPMiddleware<{ permissions: number[]}> = (next) => async (context, props) => {
if (context.locale === 'en')
return {
redirect: {
destination: '/en',
permanent: true,
},
};
const permissions = [1, 2, 3];
return next(context, { ...props, permissions });
};
const getServerSideProps = async (context: GetServerSidePropsContext) =>
withToken(
withPermissions(async (context, props) => { // props: {token: string} & {permissions: number[]}
const data = "data";
return { props: { ...props, data } };
})
)(context, {});
const MyPage: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (props) => {
const { token, permissions, data } = props; // types should infer correctly!
return null;
};
// My attempt, completely wrong
type GSSPMiddleware<Params extends { [key: string]: any } | undefined = undefined> = <
P extends { [key: string]: any } = { [key: string]: any },
>(
next: (
context: GetServerSidePropsContext,
props: Params extends undefined ? P : P & Params
) => Promise<GetServerSidePropsResult<Params extends undefined ? P : P & Params>>
) => (
context: GetServerSidePropsContext,
props: P
) => Promise<GetServerSidePropsResult<Params extends undefined ? P : P & Params>>;
How can I effectively refactor this code and define the appropriate type?