Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Argument and Return Types from GetServerSideProps #10980

Closed
defrex opened this issue Mar 11, 2020 · 7 comments
Closed

Separate Argument and Return Types from GetServerSideProps #10980

defrex opened this issue Mar 11, 2020 · 7 comments

Comments

@defrex
Copy link

defrex commented Mar 11, 2020

Feature request

Is your feature request related to a problem? Please describe.

In the 9.3 docs, the TypeScript solution for getServerSideProps is as follows.

import { GetServerSideProps } from 'next'

export const getServerSideProps: GetServerSideProps = async context => {
  // ...
}

This isn't ideal for two reasons.

One, you can't use a function statement. Not the end of the world, of course, but could be problematic for some teams if they have standards around top-level functions using function.

Two, it forces you to return a promise. If you happen to be doing something synchronously, but need it to happen on the server, you are forced to return Promise.resolve({}) or something similar.

The issues are admittedly minor, but so would be the solution.

Describe the solution you'd like

This is how GetServerSideProps is defined.

export type GetServerSideProps = (context: {
  req: IncomingMessage
  res: ServerResponse
  params?: ParsedUrlQuery
  query: ParsedUrlQuery
  preview?: boolean
  previewData?: any
}) => Promise<{ [key: string]: any }>

If that was changed to the following, it would be easy to solve these issues.

export type GetServerSidePropsContext = {
  req: IncomingMessage
  res: ServerResponse
  params?: ParsedUrlQuery
  query: ParsedUrlQuery
  preview?: boolean
  previewData?: any
}
export type GetServerSidePropsReturn = Promise<{ [key: string]: any }>
export type GetServerSideProps = (context: GetServerSidePropsContext) => GetServerSidePropsReturn
@defrex
Copy link
Author

defrex commented Mar 11, 2020

Happy to make a PR if the answer is 👍.

@jstcki
Copy link
Contributor

jstcki commented Mar 11, 2020

@defrex FYI, I proposed a different approach (doesn't solve the function statement issue though): #10856.

BTW, when declaring an async function, the return type will always be a Promise.

// This works!
async function f(): Promise<string> { return "foo"; }

@majelbstoat
Copy link

majelbstoat commented Mar 12, 2020

I'd like to combine these ideas with allowing GetServersideProps to be parameterised.

At the moment, I can't type the params or query that i'll get into the function:

export const getServerSideProps: GetServerSideProps = async ({ query }) => {
  const { username } = query // Error username is not defined on {[key: string]: any}
}

Also, I can't strongly match the return type to the props that my function will receive. I would like:

export type GetServerSidePropsContext<Query = ParsedUrlQuery> = {
  req: IncomingMessage
  res: ServerResponse
  params?: ParsedUrlQuery
  query: Query
  preview?: boolean
  previewData?: any
}
export type GetServerSidePropsReturn<Props = {[key: string]: any}> = Promise<{ props: Props }>
export type GetServerSideProps<Query = ParsedUrlQuery, Props = {[key: string]: any}> = (context: GetServerSidePropsContext<Query>) => GetServerSidePropsReturn<Props>

With that, I can define:

type User {
  id: string
}

type MyPageProps = {
  user: User
}

type MyPageQuery = {
  username: string
}

const ProfilePage: NextPage<MyPageProps> = ({ user }) => {
  const { id } = user
  // ...
}

export const getServerSideProps: GetServerSideProps<MyPageQuery, MyPageProps> = async ({ params }) => {
  const username = query.username
  const user: User = getUser(username)
  return { props: { user } }
}

Thoughts?

(edit: updated to use query instead of params, because it is the merge of both query strings and path parameters, and more useful)

@danilofuchs
Copy link

danilofuchs commented Mar 16, 2020

As a workaround while this isn't merged, if you need to get access to the context types:

type GetServerSidePropsContext = Parameters<GetServerSideProps>[0];
type GetStaticPropsContext = Parameters<GetStaticProps>[0];

@Timer
Copy link
Member

Timer commented Sep 10, 2020

This has been done in the latest Next.js version:

export type GetServerSidePropsResult<P> = {
  props?: P
  unstable_redirect?: Redirect
}

export type GetServerSideProps<
  P extends { [key: string]: any } = { [key: string]: any },
  Q extends ParsedUrlQuery = ParsedUrlQuery
> = (
  context: GetServerSidePropsContext<Q>
) => Promise<GetServerSidePropsResult<P>>

@Timer Timer closed this as completed Sep 10, 2020
@hems
Copy link

hems commented Sep 28, 2020

This has been done in the latest Next.js version:

I believe this still only on the canary branch?

I tried to add the latest version of next.js to my package.json but i could not because it's a mono repo and turns out there isn't a simple way - that i know - for adding subfolder to the repo.

Is there a simple way of adding the latest commit to the package.json file of a project that relies on a canary version?

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants