首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Typescript:带有@material-ui的通用道具的React.forwardRef

Typescript:带有@material-ui的通用道具的React.forwardRef
EN

Stack Overflow用户
提问于 2020-06-30 00:42:32
回答 1查看 1.4K关注 0票数 7

我正在尝试在@material-ui按钮component.To之上添加自定义逻辑。这样做,我正在创建一个包装原始按钮的组件,它可以正常运行。

我的问题是正确地键入它,特别是从原始组件中获取道具。在添加React.forwardRef()之前,我一直在关注https://material-ui.com/guides/typescript/#usage-of-component-prop,让它正常工作。

不带forwardRef的工作版本

代码语言:javascript
复制
import { Button, ButtonProps } from '@material-ui/core'
import React from 'react'

type ExtraProps = {
  target?: string
  rel?: string
  href?: string
  color?: 'default' | 'primary' | 'secondary'
}

// see https://material-ui.com/guides/typescript/#usage-of-component-prop
type Props<C extends React.ElementType> = ButtonProps<C, { component?: C }> & ExtraProps

const CustomButton = <C extends React.ElementType>({
  children,
  target,
  rel,
  href,
  ...rest
}: Props<C>) => {
  const relValue = target === '_blank' ? 'noopener noreferrer' : rel

  const linkValues = href ? { href, target, rel: relValue } : undefined

  return (
    <Button {...linkValues} {...rest}>
      {children}
    </Button>
  )
}

使用React.forwardRef的非工作版本

代码语言:javascript
复制
import { Button, ButtonProps } from '@material-ui/core'
import React from 'react'

type ExtraProps = {
  target?: string
  rel?: string
  href?: string
  color?: 'default' | 'primary' | 'secondary'
}

// see https://material-ui.com/guides/typescript/#usage-of-component-prop
export type Props<C extends React.ElementType> = ButtonProps<C, { component?: C }> & ExtraProps

const CustomButton = React.forwardRef<HTMLButtonElement, Props<React.ElementType>>(
  ({ children, target, rel, href, ...rest }, ref) => {
    const relValue = target === '_blank' ? 'noopener noreferrer' : rel

    const linkValues = href ? { href, target, rel: relValue } : undefined

    return (
      <Button {...linkValues} {...rest} ref={ref}>
        {children}
      </Button>
    )
  }
)

当我说“非工作”时,是因为CustomButton的类型是:

代码语言:javascript
复制
React.ForwardRefExoticComponent<Pick<Props<React.ElementType<any>>, string | number | symbol> & React.RefAttributes<HTMLButtonElement>>

而不是

代码语言:javascript
复制
<C extends React.ElementType<any>>({ children, target, rel, href, ...rest }: Props<C>) => JSX.Element

这意味着我可以将任何道具传递给我的CustomButton,而TS根本不会强制执行该合同。

我应该如何用React.forwardRef()修复版本才能有正确的输入?

Codesandbox演示:https://codesandbox.io/s/boring-hertz-0hutt?file=/src/App.tsx

EN

回答 1

Stack Overflow用户

发布于 2020-12-15 17:01:15

forwardRef不是通用的。这是万恶之源。我也在努力实现类型安全。现在我有这样的解决方案:

代码语言:javascript
复制
type As = 'button' | 'a' | 'span';

type Element<T extends As = 'button'> = T extends 'span'
    ? HTMLSpanElement
    : T extends 'a'
    ? HTMLAnchorElement
    : HTMLButtonElement;

interface CommonButtonProps<T extends As> {
    view?: View;
    size?: Size;
    disabled?: boolean;
    iconLeft?: ReactElement;
    iconRight?: ReactElement;
    className?: string;
    progress?: boolean;
    baseElement?: T;
}

export type ButtonProps<T extends As = 'button'> = CommonButtonProps<T> &
    (T extends 'a'
        ? JSX.IntrinsicElements['a']
        : T extends 'span'
        ? JSX.IntrinsicElements['span']
        : T extends undefined
        ? JSX.IntrinsicElements['button']
        : JSX.IntrinsicElements['button']);

const Button = (
    { children, baseElement, ...props }: PropsWithChildren<ButtonProps<As>>,
    ref: React.Ref<Element<As>>,
) => {
    return (
        <StyledButton {...props} as={baseElement} ref={ref}>
            {children}
        </StyledButton>
    );
};

function genericForwardRef<T extends ForwardRefRenderFunction<any, any>>(Component: T) {
    const ForwardedComponent = forwardRef(Component);

    return <U extends As = 'button'>(
        props: PropsWithChildren<PropsWithoutRef<ButtonProps<U>> & RefAttributes<Element<U>>>,
    ) => <ForwardedComponent {...props} />;
}

export default genericForwardRef(Button);

(注:我正在使用带样式的组件)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62642843

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档