如何为带静态属性的React类组件指定TypeScript类型
现有一个带静态meta属性的React类组件Rect:
// RectTool.tsx class Rect extends React.PureComponent { static meta = { icon: <AnotherComponent />, initial: { width: 50, height: 50, }, }; render() { return ( <div>Hello World</div> ); } }
将该组件传入Designer组件的tools属性:
// DesignerUI.tsx <Designer tools={[Rect]} />
尝试为Designer的tools Props定义类型时:
// DesignerUI.tsx interface Props { tools: Array< React.PureComponent & { meta: { icon: JSX.Element; initial: { width: number; height: number; strokeWidth: number }; }; } >; }
TypeScript抛出报错:
Type 'typeof Rect' is not assignable to type 'PureComponent<{}, {}, any> & { meta: { icon: Element; initial: { width: number; height: number; strokeWidth: number; }; }; }'.
Type 'typeof Rect' is missing the following properties from type 'PureComponent<{}, {}, any>': context, setState, forceUpdate, render, and 3 more.ts(2322)
当前类型定义错误地将tools数组的元素指定为React.PureComponent的实例类型,但实际传入的是组件类本身(typeof Rect),两者类型不匹配:实例类型包含context、setState等实例方法/属性,而组件类是构造函数类型,自然缺失这些实例属性,导致类型报错。
方案1:针对类组件构造函数定义类型
先提取meta的类型,再定义包含静态meta的PureComponent构造函数类型:
import React from 'react'; // 定义工具组件的meta类型 interface ToolMeta { icon: JSX.Element; initial: { width: number; height: number; strokeWidth: number; }; } // 定义带有静态meta的PureComponent构造函数类型 type PureToolComponent = typeof React.PureComponent & { meta: ToolMeta; }; // Designer组件的Props类型 interface Props { tools: PureToolComponent[]; }
方案2:兼容函数组件的通用类型
如果后续需要支持函数组件作为工具,可使用React.ComponentType(兼容类组件和函数组件)结合静态meta属性:
import React from 'react'; interface ToolMeta { icon: JSX.Element; initial: { width: number; height: number; strokeWidth: number; }; } // 定义带有静态meta的通用组件类型 type ToolComponent<T = {}> = React.ComponentType<T> & { meta: ToolMeta; }; interface Props { tools: ToolComponent[]; }
原Rect组件的meta.initial仅包含width和height,但类型定义中要求strokeWidth为必填项,需二选一调整:
- 给
Rect的meta.initial补充strokeWidth字段:static meta = { icon: <AnotherComponent />, initial: { width: 50, height: 50, strokeWidth: 2, // 补充必填字段 }, }; - 或把
ToolMeta中的strokeWidth设为可选:initial: { width: number; height: number; strokeWidth?: number; // 改为可选 };
内容的提问来源于stack exchange,提问作者Mohsen Taleb

