definitelytyped - Using getInitialProps in Next.js with TypeScript

ID : 131368

viewed : 10

Tags : typescriptdefinitelytypednextjstypescript

Top 5 Answer for definitelytyped - Using getInitialProps in Next.js with TypeScript

vote vote

90

Edit 2021/04/23: My answer below is also out of date

Please see the Next.js docs for the current recommendation for typing data fetching methods using new types and named exports.

tl;dr:

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'  export const getStaticProps: GetStaticProps = async (context) => {   // ... }  export const getStaticPaths: GetStaticPaths = async () => {   // ... }  export const getServerSideProps: GetServerSideProps = async (context) => {   // ... }  

Out of date (but functional) answer:

The above answers are out of date since Next.js now officially supports TypeScript (announcement here)

Part of this release is better TypeScript types, with much of Next.js being written in TypeScript itself. This means that the @types/next package will be deprecated in favour of the official Next.js typings.

Instead, you should import the NextPage type and assign that to your component. You can also type getInitialProps using the NextPageContext type.

import { NextPage, NextPageContext } from 'next';  const MyComponent: NextPage<MyPropsInterface> = props => (   // ... )  interface Context extends NextPageContext {   // any modifications to the default context, e.g. query types }  MyComponent.getInitialProps = async (ctx: Context) => {   // ...   return props }  
vote vote

81

EDIT: this answer is out of date since the release of Next 9. See answer above.

The classical way to solve the problem is to declare getInitialProps as a static member:

class MyComponent extends React.Component<{...}, {}> {    static async getInitialProps(ctx: any) {     return {...}   }    render() {...}  } 

When working with stateless components, you can declare a simple extension of React.SFC:

interface StatelessPage<P = {}> extends React.SFC<P> {   getInitialProps?: (ctx: any) => Promise<P> }  const MyComponent: StatelessPage<{...}> = (...) => ...  MyComponent.getInitialProps = async (ctx) => {...} 
vote vote

79

Types for Next.js are maintained in the DefinitelyTyped project which has a new version 7.0.6.

In order to use the new types, make sure you are importing them in your project:

npm install --save-dev @types/next@7.0.6 

Here is how you type getInitialProps for a stateless functional component:

import { NextFunctionComponent, NextContext } from 'next'  // Define what an individual item looks like interface IDataObject {   id: number,   name: string }  // Define the props that getInitialProps will inject into the component interface IListComponentProps {   items: IDataObject[] }  const List: NextFunctionComponent<IListComponentProps> = ({ items }) => (   <ul>     {items.map((item) => (       <li key={item.id}>         {item.id} -- {item.name}       </li>     ))}   </ul> )  List.getInitialProps = async ({ pathname }: NextContext) => {   const dataArray: IDataObject[] =     [{ id: 101, name: 'larry' }, { id: 102, name: 'sam' }, { id: 103, name: 'jill' }, { id: 104, name: pathname }]    return { items: dataArray } }  export default List 

Here is how you type getInitialProps for a class:

import React from 'react' import { NextContext } from 'next'  // Define what an individual item looks like interface IDataObject {   id: number,   name: string }  // Define the props that getInitialProps will inject into the component interface IListClassProps {   items: IDataObject[] }  class List extends React.Component<IListClassProps> {   static async getInitialProps({ pathname }: NextContext) {     const dataArray: IDataObject[] =       [{ id: 101, name: 'larry' }, { id: 102, name: 'sam' }, { id: 103, name: 'jill' }, { id: 104, name: pathname }]      return { items: dataArray }   }    render() {     return (       <ul>         {this.props.items.map((item) => (           <li key={item.id}>             {item.id} -- {item.name}           </li>         ))}       </ul>     )   } }  export default List 

If you review the tests in DefinitelyTyped, you can get a lot of insights on how to use other variations of the typings for Next.

vote vote

69

Following the documentation

import React from 'react' import { NextPageContext } from 'next'  interface Props {   userAgent?: string; }  export default class Page extends React.Component<Props> {   static async getInitialProps({ req }: NextPageContext) {     const userAgent = req ? req.headers['user-agent'] : navigator.userAgent     return { userAgent }   }    render() {     const { userAgent } = this.props     return <main>Your user agent: {userAgent}</main>   } } 
vote vote

60

Easy solution is declare type:

declare global {    namespace React {       interface FunctionComponent<P = {}> {       getInitialProps(): void; }}} 

Top 3 video Explaining definitelytyped - Using getInitialProps in Next.js with TypeScript

Related QUESTION?