在 TypeScript 的 React 组件中实现“as”属性

Dat*_*yen 8 typescript reactjs

我正在实现一个通用组件,它接受asprop 作为 TypeScript 中的任何 HTML 元素。

<Component as='div' {...myProps} {...divProps} />

<Component as='button' {...myProps} {...buttonProps} />
Run Code Online (Sandbox Code Playgroud)

我在尝试将组件的 prop 定义为任何 HTML 元素时迷失了方向。

请分享您的建议。

谢谢。

b3h*_*r4d 9

使用这样的东西:

interface IProps {
  as: React.ElementType;
}
export const Component = (props: IProps) => {
  const { as: Cmp = "div", ...rest } = props;

  return <Cmp {...rest} />;
};
Run Code Online (Sandbox Code Playgroud)

  • 根本不是类型安全的。 (2认同)

you*_*lil 4

以下文章描述了构建强类型多态组件。

以下是如何操作的摘要。关键点是使用react提供的2个泛型类型,这些类型是ElementType和ComponentPropsWithoutRef。ElementType 代表一个有效的 React Component 或 HTMLElement,ComponentPropsWithoutRef 可以推断 Component 或元素的 props。

import type {
  ComponentPropsWithoutRef,
  ElementType,
  PropsWithChildren,
} from 'react';

type PolymorphicAsProp<E extends ElementType> = {
  as?: E;
};

type PolymorphicProps<E extends ElementType> = PropsWithChildren<
  ComponentPropsWithoutRef<E> & PolymorphicAsProp<E>
>;

const defaultElement = 'p';

type TextProps<E extends ElementType = typeof defaultElement> =
  PolymorphicProps<E> & {
    color?: 'primary' | 'secondary';
  };

function Text<E extends ElementType = typeof defaultElement>({
  as,
  children,
  color = 'primary',
  className,
  ...restProps
}: TextProps<E>) {
  const Component = as ?? defaultElement;

  const customClassName = 'some-custom-class-name';

  return (
    <Component {...restProps} className={className + ' ' + customClassName}>
      {children}
    </Component>
  );
}
Run Code Online (Sandbox Code Playgroud)

这是Text组件的一些演示:

const Demo = () => {
  return (
    <div>
      <Text as="h1">Hello</Text>
      // With `a` you can pass href and it's strongly typed
      <Text as="a" href="/test-url">
        Hy
      </Text>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)