如何处理一个重载中存在而另一个重载中不存在的属性?
How to handle properties that exist in one overload and don't in another?
我使用 React 16 和 Typescript 3。我根据 属性 to 创建了一个 returns 按钮或 link 的组件设置与否。该组件可能获得 to 或 onClick 属性,它不能同时获得。
我发现 issue on TypeScript repository 准确描述了我的问题,它似乎已在 2.2 版本中修复,但以某种奇怪的方式,它不起作用。
为此,我创建了接口并按如下方式使用它们:
interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps { to: string }
interface ButtonProps extends GeneralProps {
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
// onClick might be as well undefined
}
function Button (props: LinkProps | ButtonProps): JSX.Element {
const Component: AnyStyledComponent = props.to ? Link : Button
return (
<Component to={props.to} onClick={props.onClick}>
{props.children}
</Component>
)
}
或者,我也试过这样写这个函数:
function Button (props: LinkProps): JSX.Element
function Button (props: ButtonProps): JSX.Element {
const Component: AnyStyledComponent = props.to ? Link : Button
return (
<Component to={props.to} onClick={props.onClick}>
{props.children}
</Component>
)
}
上面 Button 函数的第一个实现抛出两个错误,第二个只抛出第一个:
Property 'to' does not exist on type 'LinkProps | ButtonProps'. Property 'to' does not exist on type 'ButtonProps'.
Property 'onClick' does not exist on type 'LinkProps | ButtonProps'. Property 'onClick' does not exist on type 'LinkProps'.
为了避免错误,我提出了一个愚蠢的解决方法:
function Button (props: LinkProps | ButtonProps): JSX.Element {
const properties = Object.keys(props)
const to = properties.find((el) => el === 'to')
const Component: AnyStyledComponent = to ? Link : Button
return (
<Component {...props}>
{props.children}
</Component>
)
}
但是,这并不能解决我的问题,因为我仍然可以将 to 和 onClick 属性 传递给按钮组件。
我的代码中是否有某种错误阻止我实现我的目标,我应该从不同的角度来解决这个问题还是这根本不可能做到?
多亏了 jcalz 发布的帖子,我想出了一个解决方案,它确实可以按我的预期工作。我的解决方案不同(我使用接口,而不是类型),但是那个线程让我想到了使用 never 类型。我之前也用过,但是按要求属性,然后typescript要求传一个值,你传的时候typescript要求去掉。 never typed 属性必须是可选的。
interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps {
to: string
onClick?: never
}
interface ButtonProps extends GeneralProps {
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
to?: never
}
function Button (props: LinkProps | ButtonProps): JSX.Element { ... }
使用当前的解决方案,typescript 始终识别类型上存在的 to 和 onClick 这两个属性,不会抛出当我传递这两个属性中的任何一个时出错,但当我传递这两个属性时抛出错误。
我使用 React 16 和 Typescript 3。我根据 属性 to 创建了一个 returns 按钮或 link 的组件设置与否。该组件可能获得 to 或 onClick 属性,它不能同时获得。
我发现 issue on TypeScript repository 准确描述了我的问题,它似乎已在 2.2 版本中修复,但以某种奇怪的方式,它不起作用。
为此,我创建了接口并按如下方式使用它们:
interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps { to: string }
interface ButtonProps extends GeneralProps {
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
// onClick might be as well undefined
}
function Button (props: LinkProps | ButtonProps): JSX.Element {
const Component: AnyStyledComponent = props.to ? Link : Button
return (
<Component to={props.to} onClick={props.onClick}>
{props.children}
</Component>
)
}
或者,我也试过这样写这个函数:
function Button (props: LinkProps): JSX.Element
function Button (props: ButtonProps): JSX.Element {
const Component: AnyStyledComponent = props.to ? Link : Button
return (
<Component to={props.to} onClick={props.onClick}>
{props.children}
</Component>
)
}
上面 Button 函数的第一个实现抛出两个错误,第二个只抛出第一个:
Property 'to' does not exist on type 'LinkProps | ButtonProps'. Property 'to' does not exist on type 'ButtonProps'.
Property 'onClick' does not exist on type 'LinkProps | ButtonProps'. Property 'onClick' does not exist on type 'LinkProps'.
为了避免错误,我提出了一个愚蠢的解决方法:
function Button (props: LinkProps | ButtonProps): JSX.Element {
const properties = Object.keys(props)
const to = properties.find((el) => el === 'to')
const Component: AnyStyledComponent = to ? Link : Button
return (
<Component {...props}>
{props.children}
</Component>
)
}
但是,这并不能解决我的问题,因为我仍然可以将 to 和 onClick 属性 传递给按钮组件。
我的代码中是否有某种错误阻止我实现我的目标,我应该从不同的角度来解决这个问题还是这根本不可能做到?
多亏了 jcalz 发布的帖子,我想出了一个解决方案,它确实可以按我的预期工作。我的解决方案不同(我使用接口,而不是类型),但是那个线程让我想到了使用 never 类型。我之前也用过,但是按要求属性,然后typescript要求传一个值,你传的时候typescript要求去掉。 never typed 属性必须是可选的。
interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps {
to: string
onClick?: never
}
interface ButtonProps extends GeneralProps {
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
to?: never
}
function Button (props: LinkProps | ButtonProps): JSX.Element { ... }
使用当前的解决方案,typescript 始终识别类型上存在的 to 和 onClick 这两个属性,不会抛出当我传递这两个属性中的任何一个时出错,但当我传递这两个属性时抛出错误。