Consider we have a simple React component with a static property like meta here:
// RectTool.tsx
class Rect extends React.PureComponent
static meta = {
icon: <AnotherComponent />,
initial: {
width: 50,
height: 50,
},
};
render() {
return (
<div>Hello World</div>
);
}
}
Then in another component we're referencing that component as a prop:
// DesignerUI.tsx
<Designer
tools={[Rect]}
/>
How do we define the type for the tools prop in <Designer /> so that typescript would be
happy. What I'm doing right now is:
// DesignerUI.tsx
interface Props {
tools: Array<
React.PureComponent & {
meta: {
icon: JSX.Element;
initial: { width: number; height: number; strokeWidth: number };
};
}
>;
}
And typescript gives me this error:
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)
CodePudding user response:
There is no reason that a tool needs to be a React.PureComponent specifically. It seems like your requirements for your tool objects should be:
- It can be called using JSX as
<Rect/>with no props. - It has a
metaproperty with the appropriate values.
I would suggest that you define the type for your ToolMeta at the top level and use it in both the Rect and the Designer. You've already got a mismatch between initialValues in one place and initial in another. A good ToolMeta type can prevent this sort of mistake.
Personally I prefer to keep most interfaces one-level deep and break out sub-properties into their own named types.
interface ToolInitialValues {
width: number;
height: number;
strokeWidth?: number;
}
interface ToolMeta {
icon: JSX.Element;
initialValues: ToolInitialValues;
}
We can use this type in the Rect to get type-checking on the meta object:
class Rect extends React.PureComponent {
static meta: ToolMeta = {
Your tool components must have { meta: ToolMeta } to meet condition #2. For condition #1, you'll want to use the React.ComponentType type which is the type for a function component or class component. Your current React.PureComponent type actually refers to the instance rather than the class itself.
interface Props {
tools: Array<
React.ComponentType & { meta: ToolMeta }
>;
}
