不知道React Component的TypeScript定义文件的要点

时间:2019-12-04 16:45:10

标签: reactjs typescript

我知道TypeScript定义文件可以帮助我们在TypeScript中使用代码的JavaScript版本。但是我试图理解React组件的TypeScript定义文件。这些问题是面试官提出的,我不知道这些问题的答案。但是我想知道。该组件是用JavaScript编写的,但也有Typescript定义文件。

Button.js:

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';

const propTypes = {
  active: PropTypes.bool,
  'aria-label': PropTypes.string,
  block: PropTypes.bool,
  color: PropTypes.string,
  disabled: PropTypes.bool,
  outline: PropTypes.bool,
  tag: tagPropType,
  innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func, PropTypes.string]),
  onClick: PropTypes.func,
  size: PropTypes.string,
  children: PropTypes.node,
  className: PropTypes.string,
  cssModule: PropTypes.object,
  close: PropTypes.bool,
};

const defaultProps = {
  color: 'secondary',
  tag: 'button',
};

class Button extends React.Component {
  constructor(props) {
    super(props);

    this.onClick = this.onClick.bind(this);
  }

  onClick(e) {
    if (this.props.disabled) {
      e.preventDefault();
      return;
    }

    if (this.props.onClick) {
      this.props.onClick(e);
    }
  }

  render() {
    let {
      active,
      'aria-label': ariaLabel,
      block,
      className,
      close,
      cssModule,
      color,
      outline,
      size,
      tag: Tag,
      innerRef,
      ...attributes
    } = this.props;

    if (close && typeof attributes.children === 'undefined') {
      attributes.children = <span aria-hidden>×</span>;
    }

    const btnOutlineColor = `btn${outline ? '-outline' : ''}-${color}`;

    const classes = mapToCssModules(classNames(
      className,
      { close },
      close || 'btn',
      close || btnOutlineColor,
      size ? `btn-${size}` : false,
      block ? 'btn-block' : false,
      { active, disabled: this.props.disabled }
    ), cssModule);

    if (attributes.href && Tag === 'button') {
      Tag = 'a';
    }

    const defaultAriaLabel = close ? 'Close' : null;

    return (
      <Tag
        type={(Tag === 'button' && attributes.onClick) ? 'button' : undefined}
        {...attributes}
        className={classes}
        ref={innerRef}
        onClick={this.onClick}
        aria-label={ariaLabel || defaultAriaLabel}
      />
    );
  }
}

Button.propTypes = propTypes;
Button.defaultProps = defaultProps;

export default Button;

Button.d.ts:

import * as React from 'react';
import { CSSModule } from '../index';

export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
    [key: string]: any;
    outline?: boolean;
    active?: boolean;
    block?: boolean;
    color?: string;
    disabled?: boolean;
    tag?: string | React.ReactType;
    innerRef?: React.Ref<HTMLButtonElement>;
    onClick?: React.MouseEventHandler<any>;
    size?: any;
    id?: string;
    style?: React.CSSProperties;
    cssModule?: CSSModule;
}

declare class Button<T = {[key: string]: any}> extends React.Component<ButtonProps> {}
export default Button;

Button.d.ts文件中,有一个interface但是

界面中indexable-type [key: string]: any;的用途是什么?和

为什么declare class Button<T = {[key: string]: any}>是用Generic编写的。另外,此组件的JavaScript版本还有2个附加的props

children: PropTypes.node,
className: PropTypes.string,

但是为什么接口不包含这两个props的类型声明?

1 个答案:

答案 0 :(得分:1)

正如您所说的“打字稿定义文件可帮助我们在打字稿中使用javascript版本的代码”,这正是在这里完成的工作。

您的组件是使用Vanilla JS编写的,因此该组件没有类型。这意味着,当您使用<Button/>之类的组件时,其类型将为 any ,并且Typescript无法推断需要传递给该组件的道具是什么。

此定义文件的作用是声明该组件的props类型,并将其通过泛型传递给React.Component类。但是我不知道他为什么要声明这个通用的T = {[key: string]: any},这将需要更深入的分析,或者仅仅是实现错误。

然后将在运行时中使用react propTypes 对象来检查您是否传递了正确的消息,但打字稿将完全忽略它。此外,所有打字稿代码都将被转换为Vanilla JS,这意味着打字稿将在运行时不进行任何类型检查。

“此组件的javascript版本具有2个其他道具”

也许这些道具已经存在于他正在扩展的父组件中:React.ButtonHTMLAttributes