在带有 TypeScript 的 Next.js 中使用 getInitialProps

Posted

技术标签:

【中文标题】在带有 TypeScript 的 Next.js 中使用 getInitialProps【英文标题】:Using getInitialProps in Next.js with TypeScript 【发布时间】:2018-09-30 10:34:35 【问题描述】:

从文档、Next.js 5.0 公告和互联网上的各种文章来看,Next.js 似乎很好地支持 TypeScript,并且很多人都在使用它。

但这些线程表明对 Next.js 应用程序至关重要的 getInitialProps 不起作用:

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

我该如何解决?在类和功能组件中,当我执行 ComponentName.getInitialProps = async function() ... 时,我收到以下错误:

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

【问题讨论】:

【参考方案1】:

编辑 2021/04/23:我下面的答案也已过时

请参阅the Next.js docs,了解有关使用新类型和命名导出键入数据获取方法的当前建议。

tl;博士:

import  GetStaticProps, GetStaticPaths, GetServerSideProps  from 'next'

export const getStaticProps: GetStaticProps = async (context) => 
  // ...


export const getStaticPaths: GetStaticPaths = async () => 
  // ...


export const getServerSideProps: GetServerSideProps = async (context) => 
  // ...



过时(但功能正常)的答案:

由于Next.js现在正式支持TypeScript,以上答案已经过时(公告here)

此版本的一部分是更好的 TypeScript 类型,Next.js 的大部分内容都是用 TypeScript 本身编写的。这意味着 @types/next 包将被弃用,取而代之的是官方的 Next.js 类型。

相反,您应该导入 NextPage type 并将其分配给您的组件。您也可以使用NextPageContext 类型键入getInitialProps

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


【讨论】:

对于非页面的组件会是什么样子? @Alp 非页面组件不能使用getInitialProps。因此,您只需像普通的反应组件一样输入它(一些道具接口,推断的返回类型是我最喜欢的。您也可以使用React.FunctionComponent 谢谢。 “一些道具接口,推断的返回类型是我最喜欢的” - 你能详细说明一下吗?不知道会是什么样子。 @Alp interface Props propName: string; ; const MyComponent = (props: Props) =&gt; ( /* ... */ ) 有谁知道如何修复@typescript-eslint/unbound-method?它在MyComponent.getInitialProps = ... 中突出显示MyComponent【参考方案2】:

编辑:自 Next 9 发布以来,此答案已过时。请参阅上面的答案。

解决问题的经典方法是将getInitialProps声明为静态成员:

class MyComponent extends React.Component<..., > 

  static async getInitialProps(ctx: any) 
    return ...
  

  render() ...


在使用无状态组件时,可以声明React.SFC 的简单扩展:

interface StatelessPage<P = > extends React.SFC<P> 
  getInitialProps?: (ctx: any) => Promise<P>


const MyComponent: StatelessPage<...> = (...) => ...

MyComponent.getInitialProps = async (ctx) => ...

【讨论】:

虽然可用,但自 Next 9 发布以来,此答案已过时。请参阅下面有关如何使用官方 Next.js 分型的我的答案【参考方案3】:

Next.js 的类型在 DefinitelyTyped project 中维护,它有一个新版本 7.0.6。

要使用新类型,请确保将它们导入项目中:

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

这是您为无状态功能组件键入getInitialProps 的方式:

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

以下是您为课程键入getInitialProps 的方式:

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

如果您查看tests in DefinitelyTyped,您可以深入了解如何为 Next 使用其他类型的类型。

【讨论】:

虽然不错,但自 Next 9 发布以来,此答案已过时。请参阅下面的答案【参考方案4】:

遵循文档

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>
  

【讨论】:

【参考方案5】:

简单的解决方案是声明类型:

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

【讨论】:

以上是关于在带有 TypeScript 的 Next.js 中使用 getInitialProps的主要内容,如果未能解决你的问题,请参考以下文章

Next.js:在 getServerSideProps 中使用带有 TypeScript 的 next-redux-wrapper 调用 Thunks?

在带有 TypeScript 的 next.js 中使用 Router 的空安全方式

使用带有 TypeScript 的 next/image 时获取主机未配置错误

暗模式在带有 Nextjs 和 Typescript 的 Tailwind CSS V3 中不起作用

Storybook 在 React、Next.JS、Typescript 项目中找不到组件

在 TypeScript 和 Next.js 中使用绝对导入解析模块