Search code examples
reactjstypescriptinterface

Extending an HTMLProps interface throws error of incorrectly extending interface


I'm trying to extend an interface to imported from react, but I'm gettting an error: TS2430: Interface 'IProps' incorrectly extends interface 'HTMLProps<HTMLTableCellElement>'..

This is my complete code and the error message:


import cx from 'classnames';
import { HTMLProps } from 'react';

import styles from './index.module.scss';

export interface IProps extends HTMLProps<HTMLTableCellElement> {
  title?: string;
  className?: string;
  wrap?: boolean;
}

export const Th = ({ title, className, wrap, ...rest }: IProps) => {
  return (
    <th
      data-title={title}
      {...rest}
      className={cx(wrap && styles.wrap, className)}
    />
  );
};

And the error message:

ERROR in.../Th.tsx:6:18
TS2430: Interface 'IProps' incorrectly extends interface 'HTMLProps<HTMLTableCellElement>'.
  Types of property 'wrap' are incompatible.
    Type 'boolean | undefined' is not assignable to type 'string | undefined'.
      Type 'boolean' is not assignable to type 'string'.
    4 | import styles from './index.module.scss';
    5 |
  > 6 | export interface IProps extends HTMLProps<HTMLTableCellElement> {
      |                  ^^^^^^
    7 |   title?: string;
    8 |   className?: string;
    9 |   wrap?: boolean;

What I'm trying to do: I'm trying to import all the types from HTMLProps<HTMLTableCellElement> but add new ones such as wrap, ...etc. I think the error comes from the fact that className is already defined as an string inside HTMLProps<HTMLTableCellElement> and I cannot redefined this ?

What I'm expecting: I was expecting to be able to extend types from imported interfaces. I do not want to override the imported types.


Solution

  • There's an error here because it appears that HTMLProps includes the wrap attribute on textareas. I'm not exactly sure if it's specifically from textareas, though (it seems like wrap is supported for most text elements). Since this is a boolean on textarea elements, re-typing it to a string is invalid. An easy workaround would be to just rename the prop:

    export interface IProps extends HTMLProps<HTMLTableCellElement> {
        title?: string;
        className?: string;
        shouldWrapText?: boolean; // okay
    }
    
    export const Th = ({ title, className, shouldWrapText, ...rest }: IProps) => {
        return (
            <th
                data-title={title}
                {...rest}
                className={cx(shouldWrapText && styles.wrap, className)}
            />
        );
    };
    

    Playground