Typescript validation for properties of an object returned from a callback passed to a generic React component?

Viewed 468

This feels like so much achievable with TS, nevertheless, I couldn't.

This is my generic component interface:

export interface DataTableProps<T> {
  data: {
    id: string;
    view: T;
  }[];

  cellModifications?: (
    cellData: T[keyof T],
    rowId: string,
  ) => {
    [key: string]: TableCellProps & {  // trying to find better typing here for key: string
      content?: string | number | JSX.Element;
    };
  };
}

This is how I use it:

<DataTable<StatsFormatted>
      data={list}
      cellModifications={
        (cellData, id) => ({
          statName: {
            align: 'center',
            content: cellData,
          },
        })
      }
    />

So the thing is, the object returned from cellModification callback has to include only the keys that are in the list passed to the data prop. I am trying to write a TS validation for that.

What I have tried so far are:

  • I converted [key: string] in the interface to [key in key of T] and that worked great, it started to validate. However, that expected all the fields in the T object. That is not useful for my case, I only want to pass down some of them.
  • I also tried [key in key of Partial<T>]. Problem with that is that even though it checks the properties against T it still accepts any extra key. So still, not good.
  • Then, I tried this:
[key in StrictPropertyCheck<
   T,
   keyof Partial<PolicyStats['view']>,
   'bad key'
>]

which uses this

export type StrictPropertyCheck<T, TExpected, TError> = T extends TExpected
  ? Exclude<keyof T, keyof TExpected> extends never
    ? T
    : TError
  : TExpected;

and this one actually did what exactly the first thing I have tried did and gave an error expecting all the fields in T.

Does anyone see what I am doing wrong? Here is a TS Playground example

Thank you!

1 Answers

Its because of a feature called Excess Property checks. There are some tricks to overcome it but they are unreliable - Is it possible to restrict typescript object to contain only properties defined by its class?


Explanation

Excess property checks will make the object either require all existing props + any props or any props. Due to Excess Property checks, there is no option in between (ie only allow specified props). This annoying feature has been made for TypeScript to fit JavaScript. I had asked a similar problem - Typescript: variable of type doesn't type check under certain circumstances

Related