【问题标题】:Generic higher-order React component gives type errors通用高阶 React 组件给出类型错误
【发布时间】:2020-01-25 17:52:49
【问题描述】:

我正在尝试编写一个通用的 React 组件,它需要两种类型(IFooIBar)之一的 props 和一个接受所选类型的 props 的组件。

为什么以下不起作用?

Playground

import React from 'react';

interface IFoo {
  x: string;
}

interface IBar {
  x: number;
}

const foo: React.FunctionComponent<IFoo> = (props: IFoo) => {
  console.log("hello from foo!");
  return <div>foo</div>
};

const bar: React.FunctionComponent<IBar> = (props: IBar) => {
  console.log("hello from bar!");
  return <div>bar</div>
};

interface IProps<T> { 
    props: T[];
    Component: React.FunctionComponent<T>;
}


class HigherOrderComponent<T extends IBar | IFoo> extends React.Component<IProps<T>> { 
    render() {
        const { props, Component } = this.props;
        return (<div>
            {props.map(prop => <Component {...prop}/>)};
        </div>)
     }
}

这会返回以下错误:

Type 'T' is not assignable to type 'IntrinsicAttributes & T & { children?: ReactNode; }'.
  Type 'IFoo | IBar' is not assignable to type 'IntrinsicAttributes & T & { children?: ReactNode; }'.
    Type 'IFoo' is not assignable to type 'IntrinsicAttributes & T & { children?: ReactNode; }'.
      Type 'IFoo' is not assignable to type 'T'.
        'IFoo' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IFoo | IBar'.
          Type 'T' is not assignable to type 'IntrinsicAttributes'.
            Type 'IFoo | IBar' is not assignable to type 'IntrinsicAttributes'.
              Type 'IFoo' has no properties in common with type 'IntrinsicAttributes'.(2322)

【问题讨论】:

    标签: reactjs typescript higher-order-components


    【解决方案1】:

    快速解决方法是添加:

    {props.map((prop: T & {}) => <Component {...prop}/>)};
    

    我认为问题在于扩展运算符和联合类型(如果只有一种类型它可以正常工作)。我知道 TS 之前遇到过问题 :(

    希望这会有所帮助:)

    【讨论】:

    • 谢谢,接下来的问题是如何允许指定组件键。 仍然会报错。但这可能应该是另一个问题。
    • 这是因为您不能直接分配给泛型参数。这条评论很好地解释了它:stackoverflow.com/a/59363875/10468320
    【解决方案2】:

    您需要动态创建一个 HOC 类,以便包装一个组件并为它们提供正确的类型

    import React from 'react';
    
    interface IFoo {
      x: string;
    }
    
    interface IBar {
      x: number;
    }
    
    const foo: React.FunctionComponent<IFoo> = (props: IFoo) => {
        console.log("hello from foo!");
      return <div>foo</div>
    };
    
    const bar: React.FunctionComponent<IBar> = (props: IBar) => {
        console.log("hello from bar!");
      return <div>bar</div>
    };
    
    function createHOC<P extends IFoo | IBar>(Component: React.ComponentType<P>) {
      return class HigherOrderComponent extends React.Component<P> {
        render() {
            console.log(this.props.x)
            return <Component {...this.props} />
         }
      }
    }
    
    const WrapperFooComponent = createHOC(foo)
    
    const WrapperBarComponent = createHOC(bar)
    

    希望对你有帮助

    【讨论】:

    • 这里如何使用IProps?如何在HigherOrderComponent 中访问和使用IProps.props
    • 你不需要他们,修复了答案。所有道具都将在this.props 中提供,因此您可以从IFoo | IBar 访问x 属性为this.props.x
    • 嗯,我想我在写这个问题时可能过于简单化了我的问题。我现在更新了问题以更好地匹配我的问题。
    猜你喜欢
    • 2019-07-25
    • 2021-04-17
    • 2019-05-31
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多