这个Flow JS错误是什么意思?
Expected polymorphic type instead of any member of intersection type.
详细信息:
Document
在下面的导出行中抛出错误。我不明白为什么会发生这种情况或我能做些什么来解决它。 (我试着在Flow文档中查找,但仍然无法弄明白。)
// @flow
import Document, {Head, Main, NextScript} from 'next/document'
export default class IntlDocument extends Document {
static async getInitialProps (context) {
const props = await super.getInitialProps(context)
const {req: {localeDataScript}} = context
return {
...props,
localeDataScript
}
}
render () {
return (
<html>
<Head />
<body>
<Main />
<script
dangerouslySetInnerHTML={{
__html: this.props.localeDataScript
}}
/>
<NextScript />
</body>
</html>
)
}
}
next/document
类型声明是这样的:
declare module "next/document" {
import type {Component} from 'react';
declare type Context = {
pathname: string,
query: any,
req?: any,
res?: any,
xhr?: any,
err?: any,
};
declare export var Head: Class<Component<void, *, *>>;
declare export var Main: Class<Component<void, *, *>>;
declare export var NextScript: Class<Component<void, *, *>>;
declare export default Class<Component<void, *, *>> & {
getInitialProps: (ctx: Context) => Promise<*>;
renderPage(cb: Function): void;
};
}
答案 0 :(得分:0)
首先,我想要注意,您提供的代码需要一些更新才能使用Flow v0.53.0或更高版本。该版本对React的Flow注释工作方式进行了重大更改。特别是Component
类改为采用两个类型参数而不是三个。我在答案中对代码片段进行了必要的更改。
在最新版本的Flow(v0.59.0)中,错误消息报告了更多详细信息:
Error: react.js:7
7: export default class IntlDocument extends Document {
^^^^^^^^ identifier `Document`. Expected polymorphic type instead of any member of intersection type
7: export default class IntlDocument extends Document {
^^^^^^^^ intersection
Member 1:
15: declare export default Class<Component<*, *>> & {
^^^^^^^^^^^^^^^^^^^^^^ class type: type application of Component. See lib: types/next-document.js:15
Error:
9: const props = await super.getInitialProps(context)
^^^^^^^^^^^^^^^ property `getInitialProps`. Property not found in
9: const props = await super.getInitialProps(context)
^^^^^ statics of React$Component
Member 2:
v
15: declare export default Class<Component<*, *>> & {
16: getInitialProps: (ctx: Context) => Promise<*>;
17: renderPage(cb: Function): void;
18: };
^ object type. See lib: types/next-document.js:15
Error:
7: export default class IntlDocument extends Document {
^^^^^^^^ identifier `Document`. Expected polymorphic type instead of
v
15: declare export default Class<Component<*, *>> & {
16: getInitialProps: (ctx: Context) => Promise<*>;
17: renderPage(cb: Function): void;
18: };
^ object type. See lib: types/next-document.js:15
Found 1 error
有问题的交叉点类型是类型Document
("next/document"
的默认导出),它是
Class<Component<void, *, *>>
和
{
getInitialProps: (ctx: Context) => Promise<*>;
renderPage(cb: Function): void;
}
似乎意图是Document
是React的Component
类的子类,其静态方法为getInitialProps
和renderPage
。 Flow确实将getInitialProps
和renderPage
视为可在Document
上调用的方法。问题是Flow没有将它们视为用于子类化的静态方法;所以你对super.getInitialProps(context)
的电话失败了。
解决此问题的一个简单方法是将调用super.getInitialProps(context)
更改为Document.getInitialProps(context)
。
更好的解决方法是使用"next/document"
类型定义中的适当类声明替换类型交集:
declare export default class Document<Props, State = void> extends React$Component<Props, State> {
static getInitialProps(ctx: Context): Promise<Props>;
static renderPage(cb: Function): void;
}
我可以看到为什么原作者没有这样做。该类型定义文件导入Component
类型,如下所示:
import type {Component} from 'react';
在Flow中,类是值和具有相同名称的类型。您需要该值来创建子类,因为子类是在运行时存在的,并且在运行时不存在类型。该导入带来Component
类型,但不带值,如果值不在范围内,Flow将不允许您声明子类。如果你尝试,你会收到这样的错误:
types/next-document.js:26
26: declare export default class Document<Props, State = void> extends Component<Props, State> {
^^^^^^^^^ Component. type referenced from value position
2: import type {Component} from 'react';
^^^^^^^^^ type Component
原作者只导入了类型,因为不允许类型定义文件导入值 - 它们只能导入类型。作者发现他们无法正确声明子类,并使用该类型联合解决方法。
碰巧React的类型定义(内置于Flow中,参见react.js)将一些类型放入全局命名空间。这是类型定义作者有时使用的一种解决方法,因为在类型定义文件中导入问题时会出现问题。惯例是使用大写模块名称和美元符号为全局范围的类型添加前缀。因此,您可以在类型定义文件中使用React$Component
类型而无需导入它;这就是我在上面的声明中所做的。