Hasina Njaratin
Hasina Njaratin

Reputation: 481

Typescript in Reactjs How to make dynamic Props type?

I want to create a generic Table component.


type HeadCell<DataType> = {
  id: keyof DataType;
  label: string;
};

type TableProps<DataType> = {
  heads: HeadCell<DataType>[];
  rows: Array<DataType>;
};

const Table = ({ heads, rows }: TableProps) => {
  const ColumnsKeys = heads.map(
    (item: { [key: string]: any }) => item.id
  );

  return (
    <table>
      <tr>
        {heads.map((head: string, headKey: number) => {
          return (
            <th key={headKey}>{head.label}</th>
          );
        })}
      </tr>

      {rows.map((row, rowKey) => {
        return (
          <tr key={rowKey}>
            {ColumnsKeys.map((column: string, columnKey: number) => {
              return (
                <td key={columnKey}>{row[column]}</td>
              );
            })}
          </tr>
        );
      })};  

    </table>
  );
};

This way, the idea is that I can easily create Table like:

Example 1:

const heads = [
  {
    id: 'firstname',
    label: 'Firstname'
  },
  {
    id: 'lastname',
    label: 'Lastname'
  }
];

const rows = [
  {
    firstname: 'John',
    lastname: 'Adams'
  },
  {
    firstname: 'Paul',
    lastname: 'Walker'
  },
];

<Table heads={heads} rows={rows} />

Example 2:

const heads = [
  {
    id: 'company',
    label: 'Company'
  },
  {
    id: 'nb_employees',
    label: 'Number of employees'
  },
  {
    id: 'country',
    label: 'Country'
  }
];

const rows = [
  {
    company: 'Vody aho',
    nb_employees: 1590,
    country: 'Hong Kong'
  },
  {
    company: 'Royal spirit',
    nb_employees: 15,
    country: 'USA'
  },
];

<Table heads={heads} rows={rows} />

Now from a typescript point of view, I have a problem to pass the DataType which is a parameter of the type of the props TableProps

How could i handle this? Can I pass type Typescript to Props react? or is there a way to do this dynamically?

Knowing that for these 2 examples therefore :

Exemple1:

type DataType = {
  firstname: string;
  lastname: string;
}

Exemple2:

type DataType = {
  company: string;
  nb_employees: number;
  country: string;
}

How can I manage TableProps<DataType> type in react component props. Knowing that it will be a generic Table component => so DataType is practically dynamic.

Thanks

Upvotes: 8

Views: 12668

Answers (3)

Ori Drori
Ori Drori

Reputation: 191976

Use generics to infer the type from the data you pass. You'll need to convert the component from an arrow function to a standard function, because TS can't do generics with JSX in an arrow function.

Example: (sandbox).

type HeadCell<DataType> = {
  id: Extract<keyof DataType, string>;
  label: string;
};

type TableProps<DataType> = {
  heads: HeadCell<DataType>[];
  rows: Array<DataType>;
};

export function Table<T>({ heads, rows }: TableProps<T>) {
  const ColumnsKeys = heads.map((item: HeadCell<T>) => item.id);

  return (
    <table>
      <tr>
        {heads.map((head, headKey) => {
          return <th key={headKey}>{head.label}</th>;
        })}
      </tr>
      {rows.map((row, rowKey) => {
        return (
          <tr key={rowKey}>
            {ColumnsKeys.map((column: keyof T, columnKey) => {
              return <td key={columnKey}>{row[column]}</td>;
            })}
          </tr>
        );
      })}
    </table>
  );
}

Upvotes: 9

sohammondal
sohammondal

Reputation: 739

Both the above answers are correct. In case someone is wondering how to pass the custom type while invoking <Table />, here's how you can do it -


type DataType = {
  firstname: string;
  lastname: string;
}

 <Table<DataType> heads={heads} rows={rows} />


Upvotes: 1

libik
libik

Reputation: 61

This can be done with the arrow function according to typescript documentation https://wanago.io/2020/02/17/typescript-generics-discussing-naming-conventions/ Arrow functions section

 export const Table = <T,>({ heads, rows }: TableProps<T>) => {

    

Upvotes: 6

Related Questions