I am struggling with typing of the following dynamic button component which can handle either links or onClick events. This is is a simplified snippet of the component I now try to refactor to TypeScript.
import React from 'react'
import { Link } from 'react-router-dom'
type Props = {
children: React.ReactNode,
} & (
{
to: string,
type: undefined,
onClick: undefined,
} | {
to: undefined,
type: 'button' | 'submit',
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void,
}
)
export default function Button(props: Props) {
const { children, to } = props
const TagName = to ? Link : 'button'
return (
<TagName {...props}>
{children}
</TagName>
)
}
It gives me the following error:
Type '{ children: ReactNode; to: string; onClick: undefined; } | { children: ReactNode; to: undefined; onClick: (event: MouseEvent<HTMLButtonElement, MouseEvent>) => void; }' is not assignable to type 'IntrinsicAttributes'.
Type '{ children: ReactNode; to: string; onClick: undefined; }' has no properties in common with type 'IntrinsicAttributes'.
Guess I have to define the type of TagName but I can't figure out the correct type. Any advice?
It's the Link component type that causes the problem as I can get it working without it.
CodePudding user response:
add ?
for optional properties which handle the undefined values
type Props = {
children: React.ReactNode,
to?: string,
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void,
}
CodePudding user response:
Typescript won't allow you to do that due to incompatibility between your component props vs button
& link
's props type declarations.
So have a common field that can distinguish button
props and Link
props, which in this case use type
property of Props
.
import { Link } from 'react-router-dom'
type Props = {
children: React.ReactNode
} & (
| {
to: string
type: 'url'
}
| {
type: 'submit' | 'button'
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void
}
)
export default function Button(props: Props) {
if (props.type === 'url') {
return <Link {...props} />
}
return <button {...props} />
}