reactjs 类型声明.. React函数组件中的rest prop与类型脚本

oalqel3c  于 2023-01-17  发布在  React
关注(0)|答案(1)|浏览(134)

我真的厌倦了搜索这个主题。我不能处理......在功能组件中使用打印脚本接口的休息 prop 。
怎么能声明一个...休息 prop 与typescript接口或什么。
下面是我的一个简单代码示例。

应用程序tsx在此

function App() {
  const handleClick = (): void => {
    console.log('Clicked!!!');
  };

  return (
    <div>
      <div>
        <Button success rounded outline className="mb-5"> //(*className throws error says: ype '{ children: (string | Element)[]; success: true; rounded: true; outline: true; className: string; }' is not assignable to type 'IntrinsicAttributes & Props'.
  Property 'className' does not exist on type 'IntrinsicAttributes & Props'.*)
          <GoBell />
          Click Here!!
        </Button>
      </div>
      <div>
        <Button danger outline>
          <GoCloudDownload />
          Buy Now!
        </Button>
      </div>
      <div>
        <Button warning>
          <GoDatabase />
          See Deal!
        </Button>
      </div>
      <div>
        <Button secondary outline>
          Hide Ads!
        </Button>
      </div>
      <div>
        <Button primary rounded>
          Something
        </Button>
      </div>
    </div>
  );
}

export default App;

此处为按钮.tsx

import { ReactNode } from 'react';
import className from 'classnames';
import PropTypes from 'prop-types';

interface Props {
  children: ReactNode;
  primary?: boolean;
  secondary?: boolean;
  success?: boolean;
  warning?: boolean;
  danger?: boolean;
  outline?: boolean;
  rounded?: boolean;
  rest?: //What can I write here?
}

function Button({
  children,
  primary,
  secondary,
  success,
  warning,
  danger,
  outline,
  rounded,
  ...rest
}: Props) {
  const classes = className(
    rest.className, // ( *There is error says: Property 'className' does not exist on type '{ rest?: any; }'* )
    'flex items-center px-3 py-1.5 border transition',
    {
      'border-blue-500 bg-blue-500 text-white hover:bg-blue-600': primary,
      'border-gray-800 bg-gray-800 text-white hover:bg-gray-900': secondary,
      'border-green-500 bg-green-500 text-white hover:bg-green-600': success,
      'border-yellow-500 bg-yellow-500 text-white hover:bg-yellow-600': warning,
      'border-red-500 bg-red-500 text-white hover:bg-red-600': danger,
      'rounded-full': rounded,
      'bg-white': outline,
      'text-blue-500': outline && primary,
      'text-gray-800': outline && secondary,
      'text-green-500': outline && success,
      'text-yellow-500': outline && warning,
      'text-red-500': outline && danger,
    }
  );

  if (
    Number(!!primary) +
      Number(!!secondary) +
      Number(!!success) +
      Number(!!warning) +
      Number(!!danger) >
    1
  ) {
    return (
      <button className={classes}>Please select only one variation!!!</button>
    );
  }

  return (
    <button className={classes} {...rest}>
      {children}
    </button>
  );
}

export default Button;

我试过很多方法。这是我试过的一些方法;

在按钮.tsx中

1)
interface Props {
  .......
  rest?: Array<any> 
}

2)
interface Props {
  .......
  rest?: [any] 
}
3)
interface Props {
  .......
  rest?: Array<{className: string}> 
}

etc..
nr9pn0ug

nr9pn0ug1#

你可以添加一个indexer属性,但正如Chris所说,这听起来是一个非常糟糕的主意:

interface Props {
      children: ReactNode;
      primary?: boolean;
      secondary?: boolean;
      success?: boolean;
      warning?: boolean;
      danger?: boolean;
      outline?: boolean;
      rounded?: boolean;
      [p:keyof any]: any
    }

为什么这么糟糕?
首先,TS类型是一个最小的契约,所以每个类型化对象都可以有不同于其类型所指定的属性,通常你可以在用in操作符检查属性是否存在之后使用它。
其次,这听起来像是为了一个简单的类名而放弃了这么多的TS特性。
有很多更好的方法,比如添加className(好吧,好吧,我明白如果要添加大量的 prop ,这可能会很棘手)。
或者更好,extendind prop 类型:

import React from "react";
    
    type Props = {
      primary?: boolean;
    } & Omit<JSX.IntrinsicElements["button"], "className" | "ref">;
    
    const Button = React.forwardRef<HTMLButtonElement>(({
        primary = false,
        ...rest
    }: Props, ref) => {
        return (
            <button className={primary ? "primary" : ""} ref={ref} {... rest} />
        );
    });
    
    export default Button;

& Omit<JSX.IntrinsicElements["button"], "className" | "ref">JSX.IntrinsicElements["button"]的每个属性("className" | "ref"除外)添加到 prop 类型。
primary = false,不确定组件内部是true | false,这听起来比true | false | undefined更好。
React.forwardRef<HTMLButtonElement>((..., ref)将ref参数转发到另一个元素,这允许调用者在需要时访问真实的的html按钮。
JSX内部的ref={ref} {... rest}正在将ref属性和所有其他属性向下传输到按钮类

相关问题