Использование getInitialProps в Next.js с помощью TypeScript
Из документации, объявления Next.js 5.0 и различных статей в Интернете кажется, что Next.js хорошо поддерживает TypeScript, и многие используют его.
Но эти потоки предполагают, что getInitialProps
, жизненно важный для приложений Next.js, не работает:
Как я могу это исправить? Как в классе, так и в функциональных компонентах, когда я делаю ComponentName.getInitialProps = async function() {...}
я получаю следующую ошибку:
[ts] Property 'getInitialProps' does not exist on type '({ data }: { data: any; }) => Element'.
Ответы
Ответ 1
ОБНОВЛЕНИЕ: этот ответ устарел с момента выпуска 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) => {...}
Ответ 2
Приведенные выше ответы устарели, поскольку Next.js теперь официально поддерживает TypeScript (объявление здесь)
Часть этого выпуска - лучшие типы TypeScript, большая часть Next.js написана на самом TypeScript. Это означает, что пакет @types/next
будет заменен официальными наборами Next.js.
Вместо этого вы должны импортировать тип NextPage
и назначить его своему компоненту. Вы также можете ввести getInitialProps
, используя тип NextPageContext
.
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
}
Ответ 3
Типы для Next.js поддерживаются в проекте DefinitiveTyped, который имеет новую версию 7.0.6.
Чтобы использовать новые типы, убедитесь, что вы импортируете их в свой проект:
npm install --save-dev @types/[email protected]
Вот как вы вводите 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
Если вы ознакомитесь с тестами в DefiniteTyped, вы сможете получить много полезных советов о том, как использовать другие варианты типов для Next.
Ответ 4
Это не решение, но возможное обходное решение - использовать TypeScript только для серверных и общих скриптов (расширение .ts).
Для компонентов React используйте расширение .jsx и откажитесь от TypeScript. prop-types
и prop-types-exact
можно использовать вместо них - они дают проверку типа для реквизита (установите пакеты с помощью npm
).