網站搜尋

reactjs - 如何為一個 React 組件設置類型,使其可以接收另一個組件作為 prop,以及該組件的所有 props?


我有一個 React 元件 <Wrapper>,我可以如下使用:

// Assuming Link is a component that takes a `to` prop: <Link to="/somewhere">label</Link>
<Wrapped as={Link} to="/somewhere">label</Wrapped>

如果沒有傳入 as 屬性,它將假設使用 <a>。但如果傳入一個組件到 as,那麼對該組件有效的所有屬性現在也應該是 Wrapped 的有效屬性。

有沒有辦法在 TypeScript 中輸入這個?我目前正在考慮以下方向:

type Props<El extends JSX.Element = React.ReactHTMLElement<HTMLAnchorElement>> = { as: El } & React.ComponentProps<El>;
const Wrapped: React.FC<Props> = (props) => /* ... */;

然而,我不確定 JSX.Element 和/或 React.ComponentProps 是否是這裡相關的類型,而且這無法編譯,因為 El 無法傳給 ComponentProps。那裡正確的類型應該是什麼,而且像這樣的做法是否可能?

答案#1

你需要的類型是 ComponentType 和 ElementType。

import React, { ComponentType, ElementType, ReactNode } from 'react';

type WrappedProps <P = {}> = { 
  as?: ComponentType<P> | ElementType
} & P

function Wrapped<P = {}>({ as: Component = 'a', ...props }: WrappedProps<P>) {
  return (
    <Component {...props} />
  );
}

藉此,你可以做:

interface LinkProps {
  to: string,
  children: ReactNode,
}
function Link({ to, children }: LinkProps) {
  return (
    <a href={to}>{children}</a>
  );
}

function App() {
  return (
    <div>
      <Wrapped<LinkProps> as={Link} to="/foo">Something</Wrapped>
      <Wrapped as="div" style={{ margin: 10 }} />
      <Wrapped />
    </div>
  );
}