如何定义类型安全的TypeScript React组件包装器集合WrapperSet
解决方案
核心思路
你之前尝试的思路无法生效的核心原因是:TypeScript 无法对普通数组类型的每个独立元素做不同的泛型参数推断,只能统一将泛型参数收敛为 any 或 unknown。我们可以通过泛型辅助构造函数+可变元组泛型的方案,让 TypeScript 逐个推断数组中每个包装器项的类型,分别校验组件和对应 props 的匹配关系,全程不需要手动声明类型。
完整实现代码
import * as React from "react"; // 定义单个包装器项的类型:对应任意组件和它的props(自动排除wrap函数内部传入的children,用户无需手动传) type WrapperEntry<P = any> = [ React.ComponentType<P>, Omit<P, "children"> ]; // 泛型辅助构造函数:自动推导每个包装器项的类型并做校验 const defineWrappers = <T extends WrapperEntry[]>(wrappers: [...T]) => wrappers; // wrap函数实现,不需要额外改类型 function wrap(children: JSX.Element, wrappers: WrapperEntry[]): JSX.Element { let content = children; wrappers.forEach(([ComponentType, props]) => { content = <ComponentType {...props}>{content}</ComponentType>; }); return content; } // 组件定义和之前一致 const WrapperA: React.FC<{ label: string }> = ({ label, children }) => ( <> <div>WrapperA: {label}</div> {children} </> ); const WrapperB: React.FC<{ title: string }> = ({ title, children }) => ( <> <div>WrapperB: {title}</div> {children} </> ); // 使用示例 export const Container: React.FC = () => { // 用defineWrappers包裹数组,无需手动加类型标注,自动完成类型校验 const wrappers = defineWrappers([ [WrapperA, { label: "WrapperA" }], // 类型正确,无报错 [WrapperB, { title: "foo" }], // 类型正确,无报错 // 示例:写错props会直接触发TS报错 // [WrapperA, { title: "错误属性" }] // 报错:对象字面量只能指定已知属性,"title"不在类型"Omit<{ label: string; children?: React.ReactNode; }, 'children'>"中 ]); const content = <span>Original content</span>; return wrap(content, wrappers); };
兼容性说明
该方案完全兼容你使用的 TypeScript 4.3 版本,依赖的可变元组泛型、Omit 工具类型均在 TS4.3 之前已稳定支持。
内容的提问来源于stack exchange,提问作者Gordon
相关产品推荐
相关产品推荐

