问题
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