Button 组件使用 Partial 定义交叉类型后报错

来源:4-11 精益求精 - Buton 组件编码第二部分

Lawliet_ZMZ

2020-05-04

/**
 * @file Button
 */
import React from 'react';
import classNames from 'classnames';

// Button 尺寸
export enum ButtonSize {
  Large = 'large',
  Small = 'small',
}

// Button 类型
export enum ButtonType {
  Primary = 'primary',
  Default = 'default',
  Danger = 'danger',
  Link = 'link',
}

// 定义 Button 属性类型
interface BaseButtonProps {
  className?: string;
  disabled?: boolean;
  size?: ButtonSize;
  type?: ButtonType;
  href?: string;
  children: React.ReactNode;
}

// 定义交叉类型
type NativeButtonProps = BaseButtonProps &
  React.ButtonHTMLAttributes<HTMLElement>;
type AnchorButtonProps = BaseButtonProps &
  React.AnchorHTMLAttributes<HTMLElement>;

export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProps>;

function Button(props: ButtonProps) {
  // 解构属性
  const {
    disabled,
    className,
    size,
    type,
    href,
    children,
    ...restProps
  } = props;

  // 定义 class
  const classes = classNames('button', className, {
    [`button-${type}`]: type,
    [`button-${size}`]: size,
    disabled: type === ButtonType.Link && disabled,
  });

  if (type === ButtonType.Link) {
    return (
      <a className={classes} href={href} {...restProps}>
        {children}
      </a>
    );
  } else {
    return (
      <button className={classes} disabled={disabled} {...restProps}>
        {children}
      </button>
    );
  }
}

Button.defaultProps = {
  disabled: false,
  type: ButtonType.Default,
  children: '',
};

export default Button;

这是 Button 组件的代码,报错信息提示:

/Users/jackwang/Documents/ComponentLibrary/feather-ui/src/App.tsx
TypeScript error in /Users/jackwang/Documents/ComponentLibrary/feather-ui/src/App.tsx(7,15):
Type 'ButtonType.Link' is not assignable to type 'undefined'.  TS2322

     5 |   return (
     6 |     <div>
  >  7 |       <Button type={ButtonType.Link} href="https://jack-wjq.top">
       |               ^
     8 |         你好
     9 |       </Button>
    10 |       <Button type={ButtonType.Primary}>你好</Button>

index.tsx 部分的代码:

import React from 'react';
import Button, { ButtonSize, ButtonType } from './components/Button/Button';

function App() {
  return (
    <div>
      <Button type={ButtonType.Link} href="https://jack-wjq.top">
        你好
      </Button>
      <Button type={ButtonType.Primary}>你好</Button>
      <Button type={ButtonType.Danger} size={ButtonSize.Large}>
        test
      </Button>
      <Button size={ButtonSize.Small}>你好</Button>
    </div>
  );
}

export default App;

由于 TS 水平不是很好,还请老师看一看这部分的问题出在呐?

写回答

1回答

张轩

2020-05-05

同学你好 做的很认真,在课中我们故意把这个属性称之为 btnType 是有原因的,因为 button 和 link 这两个接口都有默认的 type 属性,

interface AnchorHTMLAttributes<T> extends HTMLAttributes<T> {
    type?: string;
}
interface ButtonHTMLAttributes<T> extends HTMLAttributes<T> {
    type?: 'submit' | 'reset' | 'button';
}

你在这里再使用交叉类型,由于重名,会导致最终的 type 变成 undefined,两个解决方法,

第一个:换名字,非常简单,就不会重名啦!

第二个:将AnchorHTMLAttributes 和 ButtonHTMLAttributes 都 type 属性都去掉,可以使用 typescript 内置的 Omit 方法。

type NativeButtonProps = BaseButtonProps & Omit<ButtonHTMLAttributes<HTMLElement>, 'type'>
type AnchorButtonProps = BaseButtonProps & Omit<AnchorHTMLAttributes<HTMLElement>, 'type'>

这样 那两个接口 都没有 type 属性啦,也就没问题了。

5
2
小骆驼6
谢谢老师 也遇到了同样的问题
2021-06-05
共2条回复

React18+TS高仿AntD从零到一打造组件库

设计,开发,测试,发布再到 CI/CD,从0到1造轮子

2123 学习 · 959 问题

查看课程