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

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

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

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

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

【问题讨论】:

    标签: typescript definitelytyped nextjs


    【解决方案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;
      }}}
      

      【讨论】:

        猜你喜欢
        • 2020-04-27
        • 2019-10-12
        • 2019-12-13
        • 2019-07-09
        • 2019-10-04
        • 2020-02-04
        • 1970-01-01
        • 2018-03-05
        • 2020-10-01
        相关资源
        最近更新 更多