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
meta
property 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 }
>;
}