javascript - Flow: is not a polymorphic type - Stack Overflow

i just integrated flow for the first time to check my javascript sources statically.I am struggling wit

i just integrated flow for the first time to check my javascript sources statically.

I am struggling with a error flow finds and i am not able to solve it on my own. Its about using es6 classes and inheritance. More specific i created some react Components and they should inherit some methods.

I have a Callout Component, that represents a callout message of unspecified severity. To make things a little more simple i thought about providing a ErrorMessage Component, that inherits the Callout Component. My classes Structure looks like:

React.Component
    > AbstractComponent (here i add some project-wide helpers for i18n and so on
        > Callout (this represents a pretty message on the screen)
            > ErrorMessage (this represents an error)

Flow tells me:

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/js/Components/Generic/ErrorMessage.js:14:43

statics of Callout [1] is not a polymorphic type.

     11│     icon: string
     12│ };
     13│
 [1] 14│ export default class ErrorMessage extends Callout<Props> {
     15│
     16│     static get defaultProps(): Props {
     17│         return {

The part Callout<Props> gets highlighted

I already define the Props Type for the Callout class, so this might be the problem but i cant solve it on my own.

A similar error is thrown a few lines below, where i try to access a parent method by addressing super.content (content is a get-method of Callout).

Thanks in advance

UPDATE: Why do i want to use class inheritance?

The inheritance Callout > ErrorMessage just exists to reduce redundant code, but its not necessary, so lets ignore this and talk about a more mon case:

I want to have a class AbstractComponent to make mon things in my project easier.

Some examples:

Printing of translation strings: In order to make the ponent multilingual, i created a utility class to generate translation strings, inside a ponent it works like

function render() {
    return (
        <div>
            {new Translation(
                'namespace',
                'key',
                [some, args],
                `${some} fallback message with optional ${args}`
            ).toString()}
        </div>
    )
}

In order to use this, every ponent in my stack ends up with the import statement on top

import Translation from "../Core/Translation"

or in the best case

import t from "../Core/Translation"

I use webpack to build a bundle and webpack seems to blow up the piled javascript with every import statement you use. So i figured - to reduce coding effort and bundle size - i provide a intermediate ponent class, that adds some utility methods like:

class AbstractComponent extends React.Component {

    constructor(props) {
        super(props);
        this.logger = props.logger || new Logger();
        this.api: ApiInterface = props.api || new MockApi();
    }

    translate(namespace: string, key: string, args: ?[] = null, fallback: ?string): string {
        return new Translation(namespace, key, args, fallback).toString();
    }

    svgSprite(id: string, className: string = "") {
        return (
            <SvgSprite id={id} className={className} />
        )
    }

}

I also added some other things to show you more reason for a intermediate Component class.

So, all of this works! But flow plains about missing return types and so on, thats good with me, for that purpose i want to use flow! The problem i cant solve is the inheritance itself... But for me it does make a lot of sense.

i just integrated flow for the first time to check my javascript sources statically.

I am struggling with a error flow finds and i am not able to solve it on my own. Its about using es6 classes and inheritance. More specific i created some react Components and they should inherit some methods.

I have a Callout Component, that represents a callout message of unspecified severity. To make things a little more simple i thought about providing a ErrorMessage Component, that inherits the Callout Component. My classes Structure looks like:

React.Component
    > AbstractComponent (here i add some project-wide helpers for i18n and so on
        > Callout (this represents a pretty message on the screen)
            > ErrorMessage (this represents an error)

Flow tells me:

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/js/Components/Generic/ErrorMessage.js:14:43

statics of Callout [1] is not a polymorphic type.

     11│     icon: string
     12│ };
     13│
 [1] 14│ export default class ErrorMessage extends Callout<Props> {
     15│
     16│     static get defaultProps(): Props {
     17│         return {

The part Callout<Props> gets highlighted

I already define the Props Type for the Callout class, so this might be the problem but i cant solve it on my own.

A similar error is thrown a few lines below, where i try to access a parent method by addressing super.content (content is a get-method of Callout).

Thanks in advance

UPDATE: Why do i want to use class inheritance?

The inheritance Callout > ErrorMessage just exists to reduce redundant code, but its not necessary, so lets ignore this and talk about a more mon case:

I want to have a class AbstractComponent to make mon things in my project easier.

Some examples:

Printing of translation strings: In order to make the ponent multilingual, i created a utility class to generate translation strings, inside a ponent it works like

function render() {
    return (
        <div>
            {new Translation(
                'namespace',
                'key',
                [some, args],
                `${some} fallback message with optional ${args}`
            ).toString()}
        </div>
    )
}

In order to use this, every ponent in my stack ends up with the import statement on top

import Translation from "../Core/Translation"

or in the best case

import t from "../Core/Translation"

I use webpack to build a bundle and webpack seems to blow up the piled javascript with every import statement you use. So i figured - to reduce coding effort and bundle size - i provide a intermediate ponent class, that adds some utility methods like:

class AbstractComponent extends React.Component {

    constructor(props) {
        super(props);
        this.logger = props.logger || new Logger();
        this.api: ApiInterface = props.api || new MockApi();
    }

    translate(namespace: string, key: string, args: ?[] = null, fallback: ?string): string {
        return new Translation(namespace, key, args, fallback).toString();
    }

    svgSprite(id: string, className: string = "") {
        return (
            <SvgSprite id={id} className={className} />
        )
    }

}

I also added some other things to show you more reason for a intermediate Component class.

So, all of this works! But flow plains about missing return types and so on, thats good with me, for that purpose i want to use flow! The problem i cant solve is the inheritance itself... But for me it does make a lot of sense.

Share Improve this question edited Mar 23, 2018 at 7:56 Philipp Wrann asked Mar 22, 2018 at 15:22 Philipp WrannPhilipp Wrann 1,8493 gold badges21 silver badges31 bronze badges 3
  • 3 umm is there any solid reason to use inheritance? React team strongly discourage it. – Tomasz Mularczyk Commented Mar 22, 2018 at 16:58
  • The Callout > ErrorMessage inheritance not but i would like to keep the AbstractComponent. Why? One simple example: I wrote a translation utility to output translation strings, inside a react ponent it works like {new Translation(namespace, id, args, fallback).toString()} In order to use this i need to import the Translation class, so every pnent ends up with: import Translation from "../Translation"; So i decided it would be useful to have a translate method inside of every react ponent i code, so i can simply write: this.translate(args...) – Philipp Wrann Commented Mar 22, 2018 at 19:13
  • So you tell me: Adopt your code because the react team thinks inheritance is not cool enough, they dont need it, i dont have to need it, know what? Facebook sucks. – Philipp Wrann Commented Mar 26, 2018 at 7:16
Add a ment  | 

1 Answer 1

Reset to default 3

If you really want to deal with inheritance (which I don't have an issue with, I just feel like you will probably run into issues later), you can do something like the following:

class AbstractComponent<Props: {}, State: ?{} = null> extends React.Component<Props, State> {
    api: ApiInterface

    logger: typeof Logger

    constructor(props) {
        super(props);
        this.logger = props.logger || new Logger();
        this.api = props.api || new MockApi();
    }

    translate(namespace: string, key: string, args: ?string[] = null, fallback: ?string): string {
        return new Translation(namespace, key, args, fallback).toString();
    }

    svgSprite(id: string, className: string = "") {
        return (
            <SvgSprite id={id} className={className} />
        )
    }
}

And use it like:

class Test extends AbstractComponent<{ some: string, args: string }> {
  render() {
    const { some, args } = this.props
     return (
        <div>
            {this.translate(
                'namespace',
                'key',
                [some, args],
                `${some} fallback message with optional ${args}`
            )}
        </div>
    )    
  }
}

Now, I will say that to some extent I understand where Facebook is ing from. Your ponent in this case is really already an abstract construct. And if you want this to be more flexible (let's say you have a stateless ponent that could benefit from having a logger and a translate function), you could do one of two things:

This is the defined type and translate function I'm using in both:

type CommonProps = {
  logger?: Logger,
  api?: ApiInterface,
  translate?: (namespace: string, key: string, args: ?string[], fallback: ?string) => string
}

// This should look familiar
function translate(namespace: string, key: string, args: ?string[] = null, fallback: ?string): string {
    return new Translation(namespace, key, args, fallback).toString();
}

Higher order ponent

function addCommonStuff({ logger = new Logger(), api = new MockApi(), translate = translate }: CommonProps) {
  return <Props: {}>(
    WrappedComponent: ComponentType<Props>
  ): ComponentType<
    $Diff<Props, $NonMaybeType<CommonProps>>
  > => (props: Props) => <WrappedComponent {...props} logger={logger} api={api} translate={translate} />
}

And used like:

class Test extends React.Component<{}> {}

const TestWithCommons = addCommonStuff({})(Test)

;<TestWithCommons /> 

Reusable ponent with a render prop

class Common extends React.Component<CommonProps & { render?: Function, children?: Function }, $NonMaybeType<CommonProps>> {
  state = {
    logger: this.props.logger || new Logger(),
    api: this.props.api || new MockApi(),
    translate: translate
  }

  render() {
    const { children, render } = this.props

    return typeof render === 'function' ? render(this.state) : (
      typeof children === 'function' ? children(this.state) : null
    )
  }
}

And use it like this:

class TestCommon extends React.Component<{}> {
   render() {
     return <Common>
       {({ logger, api, translate }) => translate('namespace',
        'key',
        null,
        `Fallback message`
      )}
    </Common>
   }
}

As an aside to this discussion, you don't need to write defaultProps as a getter for your callout. static defaultProps = {} should be enough. It shouldn't take passed in props into account or anything. If it does, you're better off using state

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745624732a4636739.html

相关推荐

  • javascript - Flow: is not a polymorphic type - Stack Overflow

    i just integrated flow for the first time to check my javascript sources statically.I am struggling wit

    5小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信