简体   繁体   English

通过 React 高阶组件传递子道具的正确 TypeScript 类型

[英]Correct TypeScript types for passing children props through a React higher order component

Consider the following code, containing a higher order component, a functional component, and a component created using the HOC and our functional component:考虑以下代码,其中包含一个高阶组件、一个功能组件以及一个使用 HOC 和我们的功能组件创建的组件:

interface InjectedProps {
  someProp?: number;
}

const myHoc = <P extends {}>(
  Component: ComponentType<P>
) => ({someProp, ...props}: P & InjectedProps) => {
  return <Component {...props as P} />;
}

const MyComponent = (props: {children?: React.ReactNode}) => {
  return <div>{props.children}</div>;
};

const WrappedComponent = myHoc(MyComponent);

However, when we try and use this new WrappedComponent :但是,当我们尝试使用这个新的WrappedComponent

return (
  <WrappedComponent>
    <h1>Hello</h1>
    <h2>World</h2>
  </WrappedComponent>
);

We end up with the error: Type '{ children: Element[]; }' has no properties in common with type 'IntrinsicAttributes & InjectedProps'.我们最终得到了错误: Type '{ children: Element[]; }' has no properties in common with type 'IntrinsicAttributes & InjectedProps'. Type '{ children: Element[]; }' has no properties in common with type 'IntrinsicAttributes & InjectedProps'. . .

This can be solved by injecting the children prop into the props of the HOC, like so;这可以通过将children prop 注入 HOC 的 props 来解决,像这样;

interface InjectedProps {
  someProp?: number;
  children?: React.ReactNode;
}

However, we now have the problem of all wrapped components can now take on children , even when they could previously not.然而,我们现在面临的问题是所有包装的组件现在都可以带子组件,即使它们以前不能。

My question is, what is the proper typing for a higher order component which passes down the children in the wrapped component?我的问题是,在包装组件中传递子代的高阶组件的正确类型是什么?

You see this error because P extends {} , whereas it should extends P extends { children?: React.ReactNode; }你看到这个错误是因为P extends {} ,而它应该扩展P extends { children?: React.ReactNode; } P extends { children?: React.ReactNode; } because you want to provide children . P extends { children?: React.ReactNode; }因为你想提供children

Btw, it is considered a bad practice to use just empty object {} as a generic constraint.顺便说一句,仅使用空对象{}作为通用约束被认为是一种不好的做法。 You should use Record<PropertyKey, unknown> instead {} .您应该使用Record<PropertyKey, unknown>代替{}

Also, you should use ComponentType<Omit<P & InjectedProps, "someProp">> instead of ComponentType<P> because this is how TS infers this type.此外,您应该使用ComponentType<Omit<P & InjectedProps, "someProp">>而不是ComponentType<P>因为这是 TS 推断此类型的方式。

Working code:工作代码:

import React, { FC, ComponentType } from 'react'

interface InjectedProps {
    someProp?: number;
}

type WithChildren = {
    children?: React.ReactNode;
}

const myHoc = <P extends WithChildren>(
    Component: ComponentType<Omit<P & InjectedProps, "someProp">>
) => ({ someProp, ...props }: P & InjectedProps) => <Component {...props} />

const MyComponent: FC = (props) => <div>{props.children}</div>

const WrappedComponent = myHoc(MyComponent);

const App = () => (
    <WrappedComponent>
        <h1>Hello</h1>
        <h2>World</h2>
    </WrappedComponent>
)

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM