如何有条件地渲染按钮 /链接Next.js组件使用Typescript

发布于 2025-02-13 00:24:15 字数 1844 浏览 1 评论 0原文

我遇到了一个非常烦人的问题,是我在有条件地渲染下一个链接链接组件或按钮元素时会遇到一堆打字稿错误。 因此,如果通过HREF支柱,我想渲染Next.js内置链接组件,否则应该是按钮。 这只是

Type 'HTMLAnchorElement' is missing the following properties from type 'HTMLButtonElement': disabled, form, formAction, formEnctype, and 11 more.ts(2322)

我不知道如何让打字稿理解的一个示例的一个示例,请理解如果存在HREF Prop,请使用(ButtonAslinkProps& Aprops),如果没有,请使用ButtonasButtonProps。

我是打字稿的新手,试图将其合作仅几周,很肯定的是,这里的类型是错误的。

这是我在这里的第一篇文章,我是如此的绝望,在互联网上任何地方都找不到与此有关的任何主题。非常感谢任何帮助。该组件的代码是波纹管:

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

I ran into a very annoying problem is that I get a bunch of typescript errors, while trying to conditionally render the Next.js Link component or a button element.
So if the href prop is passed, I want to render Next.js built-in Link component, else it should be Button.
This is just one example of the error

Type 'HTMLAnchorElement' is missing the following properties from type 'HTMLButtonElement': disabled, form, formAction, formEnctype, and 11 more.ts(2322)

I don't know how to make typescript understand that please use (ButtonAsLinkProps & aProps) if the href prop is present, and use ButtonAsButtonProps if not.

I am very new to typescript, trying to work with it for only few weeks, pretty sure, that the types here are wrong.

This is my first post here, I am so desperate, can't find any topics related to this anywhere on the internet. Would really appreciate any help. The code for the component is bellow:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

好倦 2025-02-20 00:24:15

这是我一段时间以前的解决方案,我无法在没有一些打字的情况下设法做到这一点,也许使用较新的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 href="https://google.com" passHref={true}>
  <Button>link text</Button>
</Link>

Here is my solution from some time ago, I could not manage to make it without some typecasting, maybe it is possible with newer version of 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} />;

Alternatively you can remove all the logic about Next.js Link from the component and use it like that:

<Link href="https://google.com" passHref={true}>
  <Button>link text</Button>
</Link>
情绪少女 2025-02-20 00:24:15

您可以使用CSS来实现类似的事情:

<Link className={`${isDisabled ? 'pointer-events-none' : 'cursor-pointer'}`} href={`${isDisabled ? 'http://Gogogo' : ''}`>
  My dynamic link
</Link>

如果您不使用尾风CSS,则可以创建自己的类并添加指针事件:样式表中的无属性在必要时禁用链接。
祝你好运!

You can achieve something like this using CSS:

<Link className={`${isDisabled ? 'pointer-events-none' : 'cursor-pointer'}`} href={`${isDisabled ? 'http://Gogogo' : ''}`>
  My dynamic link
</Link>

If you're not using Tailwind CSS, you can create your own class and add the pointer-events: none property in your stylesheet to disable the link when necessary.
Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文