# @axa-ch/react-polymorphic-types 中文文档

规范地址：https://npmcn.com/package/%40axa-ch/react-polymorphic-types/

版本：1\.4\.2
npm 元数据更新时间：2026-08-06T09:11:38.379Z
中文译文更新时间：2026-11-07T17:05:59.549Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40axa-ch/react-polymorphic-types
原文对照：https://npmcn.com/package/%40axa-ch/react-polymorphic-types/?lang=original
项目主页：https://github.com/axa-ch/react-polymorphic-types#readme
源码仓库：https://github.com/axa-ch/react-polymorphic-types

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：22.5 kB，5 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react ^18\.0\.0 \|\| ^19\.0\.0，@types/react ^18\.0\.0 \|\| ^19\.0\.0
- 首次发布：2023-06-14T14:02:34.062Z
- 最新版本发布：2026-05-21T07:38:14.563Z
- 近 30 天下载量：4014（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 1 个）

## 中文简介

关于反应的零运行时多态组件定义

## 安装

```sh
npm install @axa-ch/react-polymorphic-types
```

也可以使用：`pnpm add @axa-ch/react-polymorphic-types`、`yarn add @axa-ch/react-polymorphic-types`、`bun add @axa-ch/react-polymorphic-types`

## README

# 反应-多态类型

[![Build Status](https://img.shields.io/github/actions/workflow/status/axa-ch/react-polymorphic-types/ci.yml?style=flat-square&branch=main)](https://github.com/axa-ch/react-polymorphic-types/actions) [![MIT License](http://img.shields.io/badge/license-MIT-000000.svg?style=flat-square)](https://npmcn.com/package/%40axa-ch/react-polymorphic-types/LICENSE) [![NPM version](https://img.shields.io/npm/v/@axa-ch/react-polymorphic-types.svg?style=flat-square)](https://npmjs.org/package/@axa-ch/react-polymorphic-types) [![NPM downloads](https://img.shields.io/npm/dm/@axa-ch/react-polymorphic-types.svg?style=flat-square)](https://npmjs.org/package/@axa-ch/react-polymorphic-types)

## 关于

**反应-多态类型** 是允许在React中创建零运行时多态组件定义的库.

## 解释

### 什么是反应多态成分?

在 React 中构建设计系统或重新使用 UI 组件时,您可能会发现需要 **多态组件**。一个多态组件是一个多能组件,可以使基于道具的不同的 HTML 基本元素或自定义组件.

反应多态构件为消费者提供了灵活性,使他们能够指定使用道具制造的所希望的元素或构件类型.

例如,让我们考虑一个多形态标题组件:

```tsx
import { createElement, ElementType, PropsWithChildren, ComponentProps } from 'react';

// Define the props for the polymorphic heading component
type HeadingProps<T extends ElementType = 'h1'> = PropsWithChildren<
  {
    as?: T;
  } & ComponentProps<T>
>;

// Define the polymorphic heading component
export const Heading = <T extends ElementType = 'h1'>({ as = 'h1', children, ...rest }: HeadingProps<T>) =>
  createElement(as, rest, children);
```

在上述例子中 `Heading` 组件可以使不同的标题级别(`h1`, (中文(简体) ), `h2`, (中文(简体) ), `h3`等)),基于: `as` 道具 (英语). 默认情况下,它使 `h1` 键.

你可以用这个 `Heading` 应用程序中的组件 :

```tsx
const App = () => (
  <article>
    <Heading>My Main Headline</Heading>
    <Heading as='h2'>A Subtitle</Heading>
    <p>A description</p>
  </article>
);
```

在这种情况下,同样的 `Heading` 组件用于制取两个不同的语义标记, `h1` 财务报告和审定财务报表 `h2`,允许您控制标题级别并保持应用程序的一致性.

多态构件为React中构建可弹性和可再使用的UI构件提供了优雅的解决方案,使您能够创建一个具有一致语义的一致设计系统.

### 这个包能解决什么问题?

使用 `as` 属性在给您提供的标记添加限制时或使用第三方组件时会变得复杂。 宣告每个组件的多态类型也可以是您想要抽象的乏味的任务.

与 `@axa-ch/react-polymorphic-types`,可以轻松地在多态反应组件中添加约束并避免冗余类型定义.

## 安装和使用

通过 npm 安装类型脚本 :

```shell
npm i @axa-ch/react-polymorphic-types -D
```

### 多态构件

以下配方为创建多形态成分提供了一个起点. 您可按规定复制并修改.

基本示例

这个例子展示了一个简单的多态标题元素. 它允许您独立定义其大小并使用道具进行标记.

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType } from 'react';
import { PolymorphicProps } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const HeadingDefaultElement: ElementType = 'h1';
// List of allowed HTML elements that can be passed via the "as" prop
export type HeadingAllowedElements = typeof HeadingDefaultElement | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export type HeadingSizes = 1 | 2 | 3 | 4 | 5 | 6;

// Component-specific props
export type HeadingOwnProps<T extends HeadingAllowedElements> = ComponentPropsWithoutRef<T> & {
  size?: HeadingSizes;
};

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type HeadingProps<T extends HeadingAllowedElements = typeof HeadingDefaultElement> = PolymorphicProps<
  HeadingOwnProps<T>,
  T,
  HeadingAllowedElements
>;

export const Heading = <T extends HeadingAllowedElements>({
  as = HeadingDefaultElement,
  size,
  className,
  children,
  ...rest
}: HeadingProps<T>) =>
  createElement(
    as,
    {
      ...rest,
      className: `${className} size-${size || 1}`,
    },
    children,
  );
```

你可以用这个 `Heading` 应用程序中的组件如下:

```tsx
const App = () => (
  <article>
    <Heading
      as='h1'
      size={2}
    >
      My Main Headline
    </Heading>
    <Heading
      as='h2'
      size={5}
    >
      A Subtitle
    </Heading>

    {/* The following component will throw a TypeScript error because 'div' elements are not allowed here */}
    <Heading
      as='div'
      size={5}
    >
      A Subtitle
    </Heading>
    <p>A description</p>
  </article>
);
```
参考文献的基本示例

这个例子与前作相似,但也允许使用React refs.

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType, forwardRef } from 'react';
import { PolymorphicProps, PolymorphicForwardedRef } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const HeadingDefaultElement: ElementType = 'h1';
// List of allowed HTML elements that can be passed via the "as" prop
export type HeadingAllowedElements = typeof HeadingDefaultElement | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export type HeadingSizes = 1 | 2 | 3 | 4 | 5 | 6;

// Component-specific props
export type HeadingOwnProps<T extends HeadingAllowedElements> = ComponentPropsWithoutRef<T> & {
  size?: HeadingSizes;
};

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type HeadingProps<T extends HeadingAllowedElements> = PolymorphicProps<
  HeadingOwnProps<T>,
  T,
  HeadingAllowedElements
>;

const HeadingInner = <T extends HeadingAllowedElements>(
  { as = HeadingDefaultElement, size, className, children, ...rest }: HeaadingProps<T>,
  // notice the use of the PolymorphicForwardedRef type here
  ref: PolymorphicForwardedRef<T>,
) =>
  createElement(
    as,
    {
      ...rest,
      ref,
      className: `${className} size-${size || 1}`,
    },
    children,
  );

// Forward refs with generics is tricky
// see also https://fettblog.eu/typescript-react-generic-forward-refs/
export const Heading = forwardRef(HeadingInner) as unknown as <T extends HeadingAllowedElements>(
  props: HeadingProps<T> & { ref?: PolymorphicForwardedRef<T> },
) => ReturnType<typeof HeadingInner>;
```

使用 `@axa-ch/react-polymorphic-types` 类型可以自动推断合适的 DOM 节点.

```tsx
const App = () => {
  // The use of HTMLHeadingElement type is safe
  const ref = useRef<HTMLHeadingElement | null>(null);

  return (
    <Heading
      ref={ref}
      as='h2'
    />
  );
};
```
与 Ref 一起反应 19 示例

这个例子与前一个相似,但与React 19 the [调试员转发起来容易多了](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop)

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType, forwardRef } from 'react';
import { PolymorphicProps, PolymorphicForwardedRef } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const HeadingDefaultElement: ElementType = 'h1';
// List of allowed HTML elements that can be passed via the "as" prop
export type HeadingAllowedElements = typeof HeadingDefaultElement | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export type HeadingSizes = 1 | 2 | 3 | 4 | 5 | 6;

// Component-specific props
export type HeadingOwnProps<T extends HeadingAllowedElements> = ComponentPropsWithoutRef<T> & {
  size?: HeadingSizes;
  ref?: PolymorphicForwardedRef<T>;
};

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type HeadingProps<T extends HeadingAllowedElements> = PolymorphicProps<
  HeadingOwnProps<T>,
  T,
  HeadingAllowedElements
>;

const Heading = <T extends HeadingAllowedElements>({
  as = HeadingDefaultElement,
  size,
  className,
  ref,
  children,
  ...rest
}: HeadingProps<T>) =>
  createElement(
    as,
    {
      ...rest,
      ref,
      className: `${className} size-${size || 1}`,
    },
    children,
  );
```

使用 `@axa-ch/react-polymorphic-types` 类型可以自动推断合适的 DOM 节点.

```tsx
const App = () => {
  // The use of HTMLHeadingElement type is safe
  const ref = useRef<HTMLHeadingElement | null>(null);

  return (
    <Heading
      ref={ref}
      as='h2'
    />
  );
};
```
带有备忘录的基本示例

这个例子显示了使用React.memo的多态成分.

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType, memo } from 'react';
import { PolymorphicProps } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const HeadingDefaultElement: ElementType = 'h1';
// List of allowed HTML elements that can be passed via the "as" prop
export type HeadingAllowedElements = typeof HeadingDefaultElement | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export type HeadingSizes = 1 | 2 | 3 | 4 | 5 | 6;

// Component-specific props
export type HeadingOwnProps<T extends HeadingAllowedElements> = ComponentPropsWithoutRef<T> & {
  size?: HeadingSizes;
};

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type HeadingProps<T extends HeadingAllowedElements> = PolymorphicProps<
  HeadingOwnProps<T>,
  T,
  HeadingAllowedElements
>;

const HeadingInner = <T extends HeadingAllowedElements>({
  as = HeadingDefaultElement,
  size,
  className,
  children,
  ...rest
}: HeadingProps<T>) =>
  createElement(
    as,
    {
      ...rest,
      className: `${className} size-${size || 1}`,
    },
    children,
  );

// Memo with generics is tricky
// see also https://fettblog.eu/typescript-react-generic-forward-refs/
export const Heading = memo(HeadingInner) as <T extends HeadingAllowedElements>(
  props: HeadingProps<T>,
) => ReturnType<typeof HeadingInner>;
```

上述部分可在不增加间接费用的情况下消耗如下:

```tsx
const App = () => (
  <>
    <Heading as='h2' />
  </>
);
```
Exotic 组件示例

多态异域组件允许您为 HTML 使用 DOM 节点或自定义渲染功能 .

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType, ExoticComponent } from 'react';
import { PolymorphicExoticProps, PolymorphicProps } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const ContainerDefaultElement: ElementType = 'div';
// List of allowed HTML elements that can be passed via the "as" prop
export type ContainerAllowedDOMElements = typeof ContainerDefaultElement | 'article' | 'section';
export type ContainerAllowedElements = ContainerAllowedDOMElements | ExoticComponent;

// Component-specific props
export type ContainerOwnProps<T extends ContainerAllowedDOMElements> = ComponentPropsWithoutRef<T>;

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type ContainerProps<T extends ContainerAllowedElements> = T extends ContainerAllowedDOMElements
  ? PolymorphicProps<ContainerOwnProps<T>, T, ContainerAllowedDOMElements>
  : PolymorphicExoticProps<ContainerOwnProps<ContainerAllowedDOMElements>, T, ContainerAllowedDOMElements>;

export const Container = <T extends ContainerAllowedElements>({
  as = ContainerDefaultElement,
  className,
  children,
  ...rest
}: ContainerProps<T>) =>
  createElement(
    as,
    {
      ...rest,
      className,
    },
    children,
  );
```

以上组件与直通HTML节点或外部异域组件相配合,例如由HTML节点提供的组件 [帧移动](https://www.framer.com/motion/)。 。 。 .

```tsx
import { motion } from 'framer-motion';

const App = () => (
  <>
    <Container as='div' />
    {/* Notice that the exotic props here will be automatically inferred */}
    <Container
      as={motion.article}
      layout
    />
  </>
);
```
带有参考文献的 Exotic 组件示例

使用 refs 的多态异域组件略为复杂,需要一些额外的代码才能正常工作.

```tsx
import { ComponentPropsWithoutRef, createElement, ElementType, ExoticComponent, forwardRef } from 'react';
import { PolymorphicProps, PolymorphicForwardedRef, PolymorphicExoticProps } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const ContainerDefaultElement: ElementType = 'div';
// List of allowed HTML elements that can be passed via the "as" prop
export type ContainerAllowedDOMElements = 'div' | 'article' | 'section';
export type ContainerAllowedElements = ContainerAllowedDOMElements | ExoticComponent;

// Component-specific props
export type ContainerOwnProps<T extends ContainerAllowedDOMElements> = ComponentPropsWithoutRef<T>;

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type ContainerProps<T extends ContainerAllowedElements> = T extends ContainerAllowedDOMElements
  ? PolymorphicProps<ContainerOwnProps<T>, T, ContainerAllowedDOMElements>
  : PolymorphicExoticProps<ContainerOwnProps<ContainerAllowedDOMElements>, T, ContainerAllowedDOMElements>;

// Forwarded ref component
const ContainerInner = <T extends ContainerAllowedElements>(
  { as = ContainerDefaultElement, className, children, ...rest }: ContainerProps<T>,
  ref: PolymorphicForwardedRef<T>,
) =>
  createElement(
    as,
    {
      ...rest,
      ref,
      className,
    },
    children,
  );

// Forward refs with generics is tricky
// see also https://fettblog.eu/typescript-react-generic-forward-refs/
export const Container = forwardRef<ContainerAllowedElements>(ContainerInner) as <T extends ContainerAllowedElements>(
  props: ContainerProps<T> & { ref?: PolymorphicForwardedRef<T> },
) => ReturnType<typeof ContainerInner>;
```

根据上述例子,DOM节点将自动被推断出,包括在使用第三方异地渲染功能时.

```tsx
import { motion } from 'framer-motion';

const App = () => {
  const div = useRef<HTMLDivElement | null>(null);
  // Article and other HTML5 tags are just of type HTMLElement
  const article = useRef<HTMLElement | null>(null);

  return (
    <>
      <Container
        ref={div}
        as='div'
      />
      <Container
        ref={article}
        as={motion.article}
        layout
      />
    </>
  );
};
```
复杂的外观/功能组件示例

这个例子结合了您组件的多渲染策略,使其消费者有最大的灵活性.

```tsx
// We need to infer the functional component properties so 'any' is used in this case
// You can also add strict types for your functional components, but it will reduce flexibility
import { ComponentPropsWithoutRef, createElement, ElementType, ExoticComponent, FC } from 'react';
import { PolymorphicFunctionalProps, PolymorphicExoticProps, PolymorphicProps } from '@axa-ch/react-polymorphic-types';

// Default HTML element if the "as" prop is not provided
export const ContainerDefaultElement: ElementType = 'div';
// List of allowed HTML elements that can be passed via the "as" prop
export type ContainerAllowedDOMElements = 'div' | 'article' | 'section';
export type ContainerAllowedElements = ContainerAllowedDOMElements | ExoticComponent | FC<any>;

// Component-specific props
export type ContainerOwnProps<T extends ContainerAllowedDOMElements> = ComponentPropsWithoutRef<T>;

// Extend own props with others inherited from the underlying element type
// Own props take precedence over the inherited ones
export type ContainerProps<T extends ContainerAllowedElements> = T extends ContainerAllowedDOMElements
  ? PolymorphicProps<ContainerOwnProps<T>, T, ContainerAllowedDOMElements>
  : T extends FC<any>
    ? PolymorphicFunctionalProps<ContainerOwnProps<ContainerAllowedDOMElements>, T, ContainerAllowedDOMElements>
    : PolymorphicExoticProps<ContainerOwnProps<ContainerAllowedDOMElements>, T, ContainerAllowedDOMElements>;

export const Container = <T extends ContainerAllowedElements>({
  as = ContainerDefaultElement,
  className,
  children,
  ...rest
}: ContainerProps<T>) =>
  createElement(
    as,
    {
      ...rest,
      className,
    },
    children,
  );
```

让我们看看如何使用上面的组件 及其所有可能的渲染选项:

```tsx
import { motion } from 'framer-motion';

type FooProps = ComponentPropsWithoutRef<'div'> & { size: 'small' | 'large'; name: string };

const Foo: FC<FooProps> = ({ className, size = 'large', ...rest }) => (
  <div
    {...rest}
    className={`${className} the-foo ${size}`}
  />
);

const App = () => (
  <>
    <Container as='div' />
    <Container
      size='small'
      name='foo'
      as={Foo}
    />
    <Container
      as={motion.div}
      layout
      animate
    />
  </>
);
```

## 贷项

没有这个工程就不会存在 [反应-多态类型](https://github.com/kripod/react-polymorphic-types)

## 常见问题

### @axa-ch/react-polymorphic-types 是什么？

关于反应的零运行时多态组件定义

### 如何安装 @axa-ch/react-polymorphic-types？

在项目目录运行 npm install @axa-ch/react-polymorphic-types，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（^18\.0\.0 \|\| ^19\.0\.0）、@types/react（^18\.0\.0 \|\| ^19\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @axa-ch/react-polymorphic-types 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @axa-ch/react-polymorphic-types 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @axa-ch/react-polymorphic-types 可以商用吗？

@axa-ch/react-polymorphic-types 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @axa-ch/react-polymorphic-types 的下载量有多少？

根据 npm 官方下载统计，@axa-ch/react-polymorphic-types 在 2026/10/08 – 2026/11/06 这 30 天内被下载 4,014 次，日均约 134 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @axa-ch/react-polymorphic-types 还在维护吗？

最新版本 1\.4\.2 发布于 2026/05/21（5 个月前）；至今共发布 16 个版本，其中过去 12 个月发布了 1 个；首次发布于 2023/06/14。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

