Typescript `typeof React.Component` does not extend interface? Trouble defining higher-order component

核能气质少年 提交于 2020-02-04 05:25:07

问题


I'm creating a higher-order component to wrap a component extending the interface:

interface ClickOutsideInterface {
  onClickOutside: (e: Event) => void
}

The factory I've created expects a React.ComponentClass implementing the ClickOutsideInterface:

  function clickOutside<P>(Component: React.ComponentClass<P> & ClickOutsideInterface){    
    return class ClickOutside extends React.Component<P, {}> { 
      /* on click outside invoke Component.onClickOutside  */

      render() {
        return(<div><Component {...this.props} /></div>)
      }
   }
}

To test the factory, I've implement a Component extending the ClickOutsideInterface

class Test extends React.Component<TProps, TState> implements ClickOutsideInterface {
  onClickOutside(event: Event): void {
    this.setState({
      closed: true
    })
  }

  render(){
    return(
      <div>{this.state.closed}</div>
    )
  }
}

But when I use the component as an argument in the function clickOutside:

const withClickOutside = clickOutside(Test)

I get the following type error for argument Test:

Argument of type 'typeof Test' is not assignable to parameter of type 'ComponentClass & ClickOutsideInterface'. Type 'typeof Test' is not assignable to type 'ClickOutsideInterface'. Property 'onClickOutside' is missing in type 'typeof Test'.

Any ideas why Typescript believes I'm not implementing the interface in Test?


回答1:


TypeScript says that you haven't implemented the interface your function requires of its argument because you indeed have not.

When you write

class A {
  //...
}

You define two types and one value.

The value, which is named A, is the class. It is the function that you call with new to create objects.

The first type, which is also named A, is the type of the objects that are created by calling the class function with new as described above.

The second type is the type of that class function. Declaring a class doesn't automatically create a name for this type but the type exists none the less because all values have a type. This type is written typeof A because it is the type of the value A, the type of the class.

Therefore, depending on what you're trying to accomplish, you need to either

Pass an instance of Test

const withClickOutside = clickOutside(new Test);

Or change your function so that it takes an object matching the type of the class itself, and not the objects it creates

function clickOutside<P>(
  Component: new () => React.ComponentClass<P> & ClickOutsideInterface
) {...}

I suspect it is the latter that you want in this case.

Lastly, while you may want it for documentation purposes which is a completely valid, I'd like to note that there's no reason to actually declare that your class even implements the interface at all. TypeScript is a structurally typed language and all interfaces are implemented by having compatible members.



来源:https://stackoverflow.com/questions/47001804/typescript-typeof-react-component-does-not-extend-interface-trouble-defining

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!