我遇到了一个非常烦人的问题,就是在尝试有条件地渲染 Next.js Link 组件或按钮元素时,出现了一堆 typescript 错误。 因此,如果传递了 href 属性,我想渲染 Next.js 内置 Link 组件,否则它应该是 Button。 这只是错误的一个示例
Type 'HTMLAnchorElement' is missing the following properties from type 'HTMLButtonElement': disabled, form, formAction, formEnctype, and 11 more.ts(2322)
我不知道如何让 typescript 理解,如果存在 href 属性,请使用 (ButtonAsLinkProps & aProps),如果不存在,请使用 ButtonAsButtonProps。
我对 typescript 非常陌生,只尝试使用它几周,很确定,这里的类型是错误的。
这是我在这里发表的第一篇文章,我非常绝望,在互联网上的任何地方都找不到与此相关的任何主题。非常感谢任何帮助。该组件的代码如下:
interface BaseProps {
children: ReactNode
primary?: boolean
className?: string
}
type ButtonAsButtonProps = BaseProps &
Omit<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, keyof BaseProps> & {
href: undefined
}
type ButtonAsLinkProps = BaseProps & LinkProps
type aProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>
type ButtonProps = (ButtonAsLinkProps & aProps) | ButtonAsButtonProps
const Button = ({
children,
className,
href,
primary,
as,
replace,
scroll,
shallow,
passHref,
prefetch,
locale,
legacyBehavior,
...rest
}: ButtonProps): JSX.Element | undefined => {
const classNames = `${commonStyles} ${primary ? primaryStyles : secondaryStyles} ${className}`
const linkProps = {
as,
replace,
scroll,
shallow,
passHref,
prefetch,
locale,
legacyBehavior,
}
if (href && linkProps) {
return (
<Link href={href} {...linkProps}>
<a {...rest}>{children}</a>
</Link>
)
}
if (!href) {
return (
<button {...rest} className={classNames}>
{children}
</button>
)
}
}
export default Button
最佳答案
这是我不久前的解决方案,如果没有一些类型转换,我无法做到这一点,也许新版本的 TS 是可能的。
import React, { ForwardedRef, forwardRef } from 'react';
import Link, { LinkProps } from 'next/link';
type ButtonProps = JSX.IntrinsicElements['button'] & {
href?: undefined;
};
type AnchorProps = JSX.IntrinsicElements['a'] & {
href: string;
} & LinkProps;
type PolymorphicProps = ButtonProps | AnchorProps;
type PolymorphicButton = {
(props: AnchorProps): JSX.Element;
(props: ButtonProps): JSX.Element;
};
const isAnchor = (props: PolymorphicProps): props is AnchorProps => {
return props.href != undefined;
};
export const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, PolymorphicProps>(
(props, ref) => {
if (isAnchor(props)) {
const { href, as, replace, scroll, shallow, passHref, prefetch, locale, ...rest } = props;
const linkProps = { href, as, replace, scroll, shallow, passHref, prefetch, locale };
return (
<Link {...linkProps}>
<a {...rest} ref={ref as ForwardedRef<HTMLAnchorElement>} />
</Link>
);
}
return (
<button
{...props}
ref={ref as ForwardedRef<HTMLButtonElement>}
type={props.type ?? 'button'}
/>
);
},
) as PolymorphicButton;
// Tests
// event object will have correct type in every case
<Button href="https://google.com" onClick={(e) => e} />;
<Button type="submit" onClick={(e) => e} />;
// @ts-expect-error target is provided, but href is not
<Button target="_blank" onClick={(e) => e} />;
<Button href="https://google.com" target="_blank" onClick={(e) => e} />;
<Button href="https://google.com" target="_blank" prefetch onClick={(e) => e} />;
// @ts-expect-error Next.js prefetch is provided, but href is not
<Button prefetch onClick={(e) => e} />;
或者,您可以从组件中删除有关 Next.js Link 的所有逻辑并像这样使用它:
<Link href="https://google.com" passHref={true}>
<Button>link text</Button>
</Link>
关于javascript - 如何有条件地渲染按钮/使用 TypeScript 链接 Next.js 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72866352/