React/TypeScript: extending a component with additional properties

as a rule of thumb it is probably better to avoid inheritance. luckily TS and react are great tools allowing that (unlike c# for example, where inheritance often saves you a bunch of boilerplate)

export interface DataTableProps {
    columns: any[];
    data: any[];
}

export class DataTable extends React.Component<DataTableProps, {}> {
   render() {
       // -- I can use this.props.columns and this.props.data --
   }
}

export type AnimalTableProps = DataTableProps & {
    onClickFunction: () => void;
};

export class AnimalTable extends React.Component<AnimalTableProps, {}> {
    render() {
        const {onClickFunction, ...tableProps} = this.props;
        // use onClickFunction however you need it
        return <DataTable {...tableProps}></DataTable>
    }
}

You'll need to make DataTable generic so that you'll be able to use an interface which extends DataTableProps:

export interface AnimalTableProps extends DataTableProps {
    onClickFunction: Function;
}

export class DataTable<T extends DataTableProps> extends React.Component<T, {}> { }

export class AnimalTable extends DataTable<AnimalTableProps> {
    render() {
        // this.props.onClickFunction should be available
    }
}

For those who need, base classes can declare required/abstract methods that all instances must implement:

import { Component } from 'react'


abstract class TestComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {
  abstract test(): string
}


type Props = {
  first: string,
  last: string,
}

type State = {
  fullName: string,
}

class MyTest extends TestComponent<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = {
      fullName: `${props.first} ${props.last}`
    }
  }

  test() {
    const { fullName } = this.state
    return fullName
  }
}


The most elegant solution that I found (without extra generic class) is

interface IBaseProps {
    name: string;
}

class Base<P> extends React.Component<P & IBaseProps, {}>{

}

interface IChildProps extends IBaseProps {
    id: number;
}

class Child extends Base<IChildProps> {
    render(): JSX.Element {
        return (
            <div>
                {this.props.id}
                {this.props.name} 
            </div>
        );
    }
}