用于添加道具的高阶组件的子组件的Typescript类型

时间:2019-07-20 12:38:30

标签: reactjs typescript

如何为Button组件(如下)添加打字稿类型,以便打字稿知道increment HOC已注入Counter函数?

我知道了渲染道具图案和挂钩。我正在专门寻找一种类型的子组件,该子组件可以通过cloneElement由父组件接收道具。

我觉得它与条件类型有关,但不确定如何应用它。这有可能吗?

import React from 'react';

const Button = ({ increment }) => (
  <button onClick={increment}>
    increment
  </button>
);

const Counter = ({ children }) => {
  const [count, setCount] = React.useState(0);
  const increment = () => setCount(count + 1)

  return (

  <div>
    count: {count}
    {React.cloneElement(children, { increment })}
  </div>
  );
}

const App = () => (
  <Counter>
    <Button>
      increment
    </Button>
  </Counter>
);

ReactDOM.render(<App />, document.getElementById('root'));

1 个答案:

答案 0 :(得分:0)

不幸的是,TypeScript处理JSX子类型的方式并不好,cloneElement也是如此。在您的情况下,Button必须具有可选的increment道具,这意味着您稍后必须检查其存在。

我建议使用以下模式:

import React, { ComponentType } from 'react';
import ReactDOM from 'react-dom';

interface InjectedCounterProps {
  increment: () => void;
}

interface ButtonOwnProps {
  foo: string;
}

type ButtonProps = ButtonOwnProps & InjectedCounterProps;

const Button = ({ increment }: ButtonProps) => (
  <button onClick={increment}>increment</button>
);

const createCounter = <P extends {}>(
  Component: ComponentType<P & InjectedCounterProps>
) => (props: P) => {
  const [count, setCount] = React.useState(0);
  const increment = () => setCount(count + 1);

  return (
    <div>
      count: {count}
      <Component {...props} increment={increment} />
    </div>
  );
};

const Counter = createCounter<ButtonOwnProps>(Button);

const App = () => <Counter foo="bar" />;

ReactDOM.render(<App />, document.getElementById('root'));

在这里,我们使用HOC从提供的Button组件中构建组件,并且能够将此按钮的类型限制为由HOC注入的按钮。

这也允许应用到返回组件的props由我们提供的组件定义。这是通过通用的P类型参数完成的,并允许我们传递ButtonOwnProps,从而在渲染最终的foo时必须提供Counter

如果在渲染foo="bar"时删除Counter,您会发现我们遇到类型错误。