diff --git a/package.json b/package.json index a1beb68feb661..51091d1b20cfa 100644 --- a/package.json +++ b/package.json @@ -135,6 +135,7 @@ "eslint-plugin-react-hooks": "4.5.0", "event-stream": "4.0.1", "execa": "2.0.3", + "expect-type": "0.14.2", "express": "4.17.0", "faker": "5.5.3", "faunadb": "2.6.1", diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 09647baa800df..7a2e2e55dc0ab 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -128,13 +128,10 @@ export type GetStaticProps< context: GetStaticPropsContext ) => Promise> | GetStaticPropsResult

-export type InferGetStaticPropsType = T extends GetStaticProps - ? P - : T extends ( - context?: GetStaticPropsContext - ) => Promise> | GetStaticPropsResult - ? P - : never +export type InferGetStaticPropsType any> = Extract< + Awaited>, + { props: any } +>['props'] export type GetStaticPathsContext = { locales?: string[] @@ -181,16 +178,9 @@ export type GetServerSideProps< context: GetServerSidePropsContext ) => Promise> -export type InferGetServerSidePropsType = T extends GetServerSideProps< - infer P, - any +export type InferGetServerSidePropsType any> = Awaited< + Extract>, { props: any }>['props'] > - ? P - : T extends ( - context?: GetServerSidePropsContext - ) => Promise> - ? P - : never declare global { interface Crypto { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c2a4f25d6209..4da886576a755 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,6 +96,7 @@ importers: eslint-plugin-react-hooks: 4.5.0 event-stream: 4.0.1 execa: 2.0.3 + expect-type: 0.14.2 express: 4.17.0 faker: 5.5.3 faunadb: 2.6.1 @@ -251,6 +252,7 @@ importers: eslint-plugin-react-hooks: 4.5.0_eslint@7.24.0 event-stream: 4.0.1 execa: 2.0.3 + expect-type: 0.14.2 express: 4.17.0 faker: 5.5.3 faunadb: 2.6.1 @@ -14088,6 +14090,13 @@ packages: homedir-polyfill: 1.0.3 dev: true + /expect-type/0.14.2: + resolution: + { + integrity: sha512-ed3+tr5ujbIYXZ8Pl/VgIphwJQ0q5tBLGGdn7Zvwt1WyPBRX83xjT5pT77P/GkuQbctx0K2ZNSSan7eruJqTCQ==, + } + dev: true + /expect/26.6.2: resolution: { diff --git a/test/unit/infer-get-server-side-props-type.test.ts b/test/unit/infer-get-server-side-props-type.test.ts new file mode 100644 index 0000000000000..abe3c195ce2d5 --- /dev/null +++ b/test/unit/infer-get-server-side-props-type.test.ts @@ -0,0 +1,69 @@ +import type { + InferGetServerSidePropsType, + GetServerSidePropsContext, +} from 'next' +import { expectTypeOf } from 'expect-type' + +describe('InferGetServerSidePropsType', () => { + it('should work with sync functions', async () => { + function getServerSideProps(context: GetServerSidePropsContext) { + if (context.params?.notFound) { + return { + notFound: true, + } + } + + return { + props: { + foo: 'bar', + }, + } + } + + type PageProps = InferGetServerSidePropsType + + expectTypeOf().toEqualTypeOf<{ foo: string }>() + }) + + it('should work with async functions', async () => { + async function getServerSideProps(context: GetServerSidePropsContext) { + if (context.params?.notFound) { + return { + notFound: true, + } + } + + if (context.params?.redirect) { + return { + redirect: { + destination: '/', + }, + } + } + + return { + props: { + foo: 'bar', + }, + } + } + + type PageProps = InferGetServerSidePropsType + + expectTypeOf().toEqualTypeOf<{ foo: string }>() + }) + + it('should work with promised props', async () => { + async function getServerSideProps() { + return { + props: Promise.resolve({ + foo: 'bar', + }), + } + } + + type PageProps = InferGetServerSidePropsType + + expectTypeOf().toEqualTypeOf<{ foo: string }>() + }) +}) diff --git a/test/unit/infer-get-static-props.test.ts b/test/unit/infer-get-static-props.test.ts new file mode 100644 index 0000000000000..3cef48a1cc530 --- /dev/null +++ b/test/unit/infer-get-static-props.test.ts @@ -0,0 +1,52 @@ +import type { InferGetStaticPropsType, GetStaticPropsContext } from 'next' +import { expectTypeOf } from 'expect-type' + +describe('InferGetServerSidePropsType', () => { + it('should work with sync functions', async () => { + function getStaticProps(context: GetStaticPropsContext) { + if (context.params?.notFound) { + return { + notFound: true, + } + } + + return { + props: { + foo: 'bar', + }, + } + } + + type PageProps = InferGetStaticPropsType + + expectTypeOf().toEqualTypeOf<{ foo: string }>() + }) + + it('should work with async functions', async () => { + async function getStaticProps(context: GetStaticPropsContext) { + if (context.params?.notFound) { + return { + notFound: true, + } + } + + if (context.params?.redirect) { + return { + redirect: { + destination: '/', + }, + } + } + + return { + props: { + foo: 'bar', + }, + } + } + + type PageProps = InferGetStaticPropsType + + expectTypeOf().toEqualTypeOf<{ foo: string }>() + }) +})