I have a button component. I simply pass it just one onClick
prop out of many optional props I've defined:
const Button = (props: ButtonProps) => {
const handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
props.onClick(e);
}
return (
<StyledButton onClick={handleClick}>
{props.children}
</StyledButton>
);
};
Then I'm using it like this:
<Button onClick={(e) => {
console.log(e);
}}>Click me!</Button>
Now how can as per the error mentioned in question, object be possibly undefined? I'm clearly passing the function to it and that too as per the type definition. So, I'm passing an object to it. Simple enough!
...
onClick?: React.MouseEventHandler<HTMLElement>
...
I've added a few more strict checks in this project recently and relevant one's are:
"strictFunctionTypes": true,
"strictNullChecks": true
strict:true
being already present, this error never occurred.
What's the issue here?
Update – Types added
export interface IBaseButtonProps {
type?: ButtonType;
disabled?: boolean;
size?: ButtonSize;
block?: boolean;
loading?: boolean | { delay?: number };
icon?: string;
className?: string;
prefixCls?: string;
children?: React.ReactNode;
}
export type AnchorButtonProps = {
href: string,
target?: string,
onClick: React.MouseEventHandler<HTMLElement>
} & IBaseButtonProps & Omit<React.AnchorHTMLAttributes<any>, 'type' | 'onClick'>;
export type NativeButtonProps = {
onClick: React.MouseEventHandler<HTMLElement>,
htmlType?: ButtonHTMLType
} & IBaseButtonProps & Omit<React.ButtonHTMLAttributes<any>, 'type' | 'onClick'>;
export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>
Notes:
The possible solution is to either destructure the props and add the default prop. Or use defaultProps
from React. But not sure if I should require that really with Typescript.
Best Answer
The use of
Partial<T>
aroundexport type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>
causesonClick
to be optional. When we usePartial<T>
, all the properties receive the?
and thus become optional, which means that all of them can be undefined.There are two approached to a fix: one is to keep
ButtonProps
the same withonClick
as optional, and to check thatonClick
is defined before calling it (fix 1); the other is to changeButtonProps
to makeonClick
required (fix 2 and 3).Fix 1:
onClick
remains optionalUse the
ButtonProps
that you already have, and then check thatonClick
is defined before calling it. This is what antd does in the code you linked in the comments.Fix 2:
onClick
becomes requiredChange
ButtonProps
by not applying thePartial
to theNativeButtonProps
:Fix 3:
onClick
becomes required tooDefine a
RequireKeys
type, which lets you to specify the keys that are not optional.The answers to Mapped Types: removing optional modifier have more information about how I defined
RequireKeys<T>
.