我正在尝试创建一个采用onClick
或to
属性的组件。
const StickyButton: React.FC<
({ onClick: MouseEventHandler } | { to: string }) & {
buttonComponent?: ({ onClick: MouseEventHandler }) => JSX.Element
} & BoxProps
> = ({
children,
onClick,
to,
buttonComponent: ButtonComponent = Button,
...props
}) => {
const handler = !!to ? () => navigate(to) : onClick
return (
<StickyBox {...props}>
<ButtonComponent onClick={handler}>{children}</ButtonComponent>
</StickyBox>
)
}
我收到以下TS错误。
TS 2339:类型“PropsWithChildren”上不存在属性“to”({ onClick:鼠标事件处理程序;}|{到:字符串;})& {按钮组件?:({单击:鼠标事件处理程序}:{ onClick:任意;})=〉元素;} & BoxProps〉'中找到的。
这是一个简化的TS游戏场
我试过了:
- 删除
React.FC
类型并简单地输入解构后的props对象--结果相同 - 删除除
onClick
和to
--{ onClick: MouseEventHandler } | { to: string }
--之外的所有其他属性,则这两个属性都会得到相同类型的错误
我还尝试了一些更“完全定义”的联合类型:
interface BasicProps extends BoxProps {
buttonComponent?: ({ onClick: MouseEventHandler }) => JSX.Element
}
interface LinkProps extends BasicProps {
to: string
}
interface ButtonProps extends BasicProps {
onClick: MouseEventHandler
}
但我得到的结果是一样的!
我希望不仅仅是我的TS编译器奇怪/慢🙃
1条答案
按热度按时间zf9nrax11#
在我看来,一切都在按预期工作。TypeScript的结构类型系统只会检查必需的属性是否存在,而不会检查额外的属性是否存在:
TypeScript的freshness概念可能会引起混淆,也称为 * 严格对象文字检查 *。通过新鲜度检查,TypeScript实际上会检查对象文字是否仅定义已知属性:
这里令人困惑的是已知属性和“额外”属性的分离。对于类型联合,可能存在 * 已知 * 但额外的属性:
问题归结起来就是TypeScript无法保证您试图解构的属性确实存在:
但是当类型系统可以保证一个属性存在于联合体的所有部分时,您就可以安全地解构该属性:
现在来看一下您的确切问题,TypeScript会告诉您问题是什么,尽管有点过于冗长:
TS 2339:类型“PropsWithChildren”上不存在属性“to”({ onClick:鼠标事件处理程序;}|{到:字符串;})& {按钮组件?:({单击:鼠标事件处理程序}:{ onClick:任意;})=〉元素;} & BoxProps〉'中找到的。
由于
StickyButton
是一个FC<Props>
,根据FC<Props>
的定义,它是一个接受Props
类型参数的函数。在您的示例中,类型Props
等于错误消息中“does not exist on type”后面的单词salad。并且TypeScript无法保证名为to
的属性将始终存在于其中。因此,它不能在函数参数中被反结构化: