You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TypeScript为React多态组件实现自闭合标签类型约束

React多态组件自闭合标签的TypeScript类型处理

需求:实现一个React多态组件,当指定as为<img/>这类自闭合标签时,组件不接受children属性,必须以自闭合形式使用;当指定为普通标签(如<div/>)时,允许传入children。

修改后的类型定义与组件实现

import React, { ReactNode } from 'react';

// 定义支持的组件类型
type Components = 'img' | 'div';
// 标记自闭合标签集合
type SelfClosingTags = 'img';

// 条件类型:根据标签类型生成对应Props
type Props<T extends Components> = 
  T extends SelfClosingTags 
    ? { as: T } // 自闭合标签无children属性
    : { as: T; children: ReactNode }; // 非自闭合标签需包含children

export default function MemoizedComponent<T extends Components>({
  as,
  children,
}: Props<T>) {
  const Component = as;
  const MemoizedComp = React.memo(Component);

  // 类型已确保:只有非自闭合标签会传入children
  return typeof children !== 'undefined' 
    ? <MemoizedComp>{children}</MemoizedComp> 
    : <MemoizedComp />;
}

示例用法(App.tsx)

import React from 'react';
import MemoizedComponent from './components/PolyComponent';

export const App = () => {
  return (
    <div className="p-2">
      <h1>React TSX Starter</h1>
      {/* ✅ 合法:div是非自闭合标签,可传入children */}
      <MemoizedComponent as="div">test</MemoizedComponent>
      
      {/* ❌ TypeScript编译报错:img是自闭合标签,不允许传入children */}
      {/* <MemoizedComponent as="img">test</MemoizedComponent> */}
      
      {/* ✅ 合法:img以自闭合形式使用 */}
      <MemoizedComponent as="img" />
    </div>
  );
};

关键说明

  • 利用**条件类型Props<T>**实现标签类型与props的强关联:当T属于自闭合标签时,props仅包含as字段;否则必须声明children。
  • TypeScript会在编译阶段拦截错误用法,无需依赖运行时判断。
  • 渲染逻辑简化:类型推断已确保children仅在非自闭合标签场景存在,直接根据children是否存在选择渲染形式即可。

内容的提问来源于stack exchange,提问作者BARNOWL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:15:34