I am trying to convert this class component to a function component but I need the component to have these static properties.
export class InputBox<T extends string|number|undefined = undefined> extends React.Component<IInputBoxProps<T>, IInputBoxState> {
static displayName = "InputBox";
static defaultProps: IInputBoxProps<string|number> = {
disabled: false,
rightAligned: false,
id: "",
keySelectIndex: 0,
}
... rest of component
}
I have tried this code:
export const InputBox: React.FunctionComponent<IInputBoxProps<any>> = <T extends string | number | undefined = undefined >(props: IInputBoxProps<T>) => {
InputBox.displayName = "InputBox";
InputBox.defaultProps = {
disabled: false,
rightAligned: false,
id: "",
keySelectIndex: 0,
}
... rest of component
}
When I run this code I get a eslint error saying that:
FunctionComponent<IInputBox<any>>' is not a constructor function type.
T = any
does not work here either. I know any
kinda makes typescript useless but I can't seem to get around the error.
How can I type a function component with a "constructor function type" and what does that mean exactly?
What is the difference between a function constructor and class constructor in a class constructor? Should I type static props differently in a function component?
CodePudding user response:
Generic Component
export const InputBox: React.FunctionComponent<IInputBoxProps<any>> = <T ...
This sort of syntax will never work properly because you are trying to set the generic T
on the function itself. The point of the generic is that the T
can be different every time the function is called.
So you cannot use the React.FunctionComponent
type here. But you don't need to -- just set the types of the props.
If your eslint settings uses the rule explicit-module-boundary-names
then you will also need to set the return type as JSX.Element
(or JSX.Element | null
if it might return null
).
Default Props
defaultProps
doesn't really exist on function components (See discussion here). Rather than trying to set the defaultProps
property on your function component, think about what that property is actually doing and how you can implement that functionality.
I would handle this by using the values from your defaultProps
as the defaults when destucturing the properties. (Note: I'm not sure what the T
here applies to).
const InputBox = <T extends string | number | undefined = undefined>(
props: IInputBoxProps<T>
) => {
const {
disabled = false,
rightAligned = false,
id = "",
keySelectIndex = 0,
// ... other props without defaults
} = props;
...
or inline
const InputBox = <T extends string | number | undefined = undefined>(
{ disabled = false, rightAligned = false, id = "", keySelectIndex = 0, data }: IInputBoxProps<T>
) => {
...
Display Name
The displayName
is not really needed because the inferred display name will be the name of the function. It will already be "InputBox"
. You should only be getting eslint errors here if you have used the option { ignoreTranspilerName: true }
.
As you can see in the rule examples, you must first create the function and then assign the displayName
property to the function. Aleksey's comment does this correctly.
const InputBox = <T extends string | number | undefined = undefined>(
props: IInputBoxProps<T>
): JSX.Element => {
/* ... */
}
InputBox.displayName = "InputBox";