这个Flow JS“多态类型而不是交集类型”错误是什么意思?

时间:2017-06-19 04:39:50

标签: javascript flowtype next.js

这个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;
  };
}

1 个答案:

答案 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类的子类,其静态方法为getInitialPropsrenderPage。 Flow确实将getInitialPropsrenderPage视为可在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类型而无需导入它;这就是我在上面的声明中所做的。