0

I know the TypeScript definition file helps us to use JavaScript version of the code with TypeScript. But I'm trying to understand the TypeScript definition file for a React component. These questions were asked by the interviewer and I don't know the answer to these questions. But I want to know. The component is written in JavaScript but also there is Typescript definition file.

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;

In Button.d.ts file, there is an interface But,

What is the purpose of indexable-type [key: string]: any; in the interface? and

Why declare class Button<T = {[key: string]: any}> is written with Generic. Also, the JavaScript version of this component has 2 additional props.

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

But why interface doesn't contain types declaration for these 2 props?

1 Answer 1

1

As you have said "typescript definition file helps us to use javascript version of the code with Typescript", and that is exactly what is been done here.

Your component is write in vanilla JS, so the component do not have types. This means that when you use the component like <Button/> his type will be any and there is no way for Typescript to infer what are the props you need to pass to the component.

What this definition file do is declare what will be the types of the props for this component and pass it to the React.Component class through generics. But i do not know exactly why he is declaring this generic T = {[key: string]: any}, this would require a deeper analyses or is just a implementation error.

And the react propTypes object just will be used in the runtime to check if you are not passing nothing wrong, but typescript will ignore it completely. Also, all typescript code will be transpiled to vanilla JS, this means that typescript will not do any type check in runtime.

"the javascript version of this component has 2 additional props"

Maybe these props already exist in the parent component he is extending: React.ButtonHTMLAttributes

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.