Using getInitialProps in Next.js with TypeScript

六眼飞鱼酱① 提交于 2020-03-13 05:50:08

问题


From the documentation, Next.js 5.0 announcement and various articles around on the internet it seems like Next.js supports TypeScript well and many people are using it.

But these threads suggest that getInitialProps, which is vital to Next.js apps, doesn't work:

  • https://github.com/zeit/next.js/issues/3396
  • https://github.com/zeit/next.js/issues/1651
  • https://github.com/DefinitelyTyped/DefinitelyTyped/issues/23356

How can I fix it? In both class and functional components, when I do ComponentName.getInitialProps = async function() {...} I get the following error:

[ts] Property 'getInitialProps' does not exist on type '({ data }: { data: any; }) => Element'.

回答1:


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
}




回答2:


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) => {...}



回答3:


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.




回答4:


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>
  }
}


来源:https://stackoverflow.com/questions/49929268/using-getinitialprops-in-next-js-with-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!