如何在React组件中结合哈希映射派生类型使用泛型?
如何通过必填type prop自动推导React泛型组件的Props类型?
我在项目里有很多结构相似的React组件,想做个泛型组件消除冗余代码。这些组件的类型都继承自同一个基础类型,我期望通过必填的type prop,结合哈希映射来确定组件该使用的Props,但用type prop推导类型时碰到了TypeScript类型错误。
现有代码实现
首先定义形状枚举:
export enum Shape{ SQUARE = "square", CIRCLE = "circle", RECTANGLE = "rectangle" }
接着为各形状创建接口,并关联枚举与对应类型的映射:
export interface SquareComponent{ side: number; color: string; } export interface CircleComponent{ radius: number; color: string; } export interface RectangleComponent{ length: number; height: number; color: string; } // 通过枚举值获取对应类型的哈希映射 export type ShapeConversion = { [T in Shape]: { [Shape.SQUARE]: SquareComponent; [Shape.CIRCLE]: CircleComponent; [Shape.RECTANGLE]: RectangleComponent; }[T] }
然后定义泛型组件的Props接口:
export interface myComponentProps<T>{ type: Shape, shapeList: T[] }
正常工作的两种写法
直接指定具体类型时,类型校验正常:
// 类型校验正常 const myComponent = ({type, shapeList}: myComponentProps<CircleComponent>) => { // 处理形状逻辑 }
通过映射指定具体枚举值时,类型校验也正常:
// 类型校验也正常 const myComponent2 = ({type, shapeList}: myComponentProps<ShapeConversion[Shape.CIRCLE]>) => { // 处理形状逻辑 }
出错的写法
尝试通过传入的type prop推导类型时,出现TypeScript错误:Type 'any' cannot be used as an index type.
// 类型校验失败 const myComponent3 = ({type, shapeList}: myComponentProps<ShapeConversion[typeof type]>) => { // 处理形状逻辑 }
解决方案:让泛型参数绑定到具体枚举值
要实现通过type prop自动推导泛型类型,需要把组件定义为泛型组件,让泛型参数绑定到type的具体枚举值上,而非直接使用typeof type(此时type是联合类型,无法直接作为索引)。
1. 调整Props接口
让泛型参数对应具体的Shape枚举值,而非直接对应组件类型:
export interface MyComponentProps<T extends Shape> { type: T; shapeList: ShapeConversion[T][]; }
2. 定义泛型组件
TypeScript会根据传入的type自动推导泛型参数T:
const MyComponent = <T extends Shape>({ type, shapeList }: MyComponentProps<T>) => { // 处理形状逻辑 return <div>{/* 渲染内容 */}</div>; };
3. 使用组件时自动推导类型
无需手动指定泛型参数,TypeScript会完全根据type的值推导shapeList的类型:
// 自动推导shapeList为CircleComponent[] <MyComponent type={Shape.CIRCLE} shapeList={[{ radius: 10, color: "red" }]} /> // 自动推导shapeList为SquareComponent[] <MyComponent type={Shape.SQUARE} shapeList={[{ side: 5, color: "blue" }]} />
额外优化:简化ShapeConversion类型
原来的映射写法可以简化为更直接的键值对形式,效果完全一致:
export type ShapeConversion = { [Shape.SQUARE]: SquareComponent; [Shape.CIRCLE]: CircleComponent; [Shape.RECTANGLE]: RectangleComponent; }
内容的提问来源于stack exchange,提问作者Jacob Conner
相关产品推荐
相关产品推荐

