Home > Software engineering >  Dynamically access element of array using generic constraints and keyof operator
Dynamically access element of array using generic constraints and keyof operator

Time:06-29

I am trying to dynamically render a table in react. The generic attributes will ensure indexing elements of the data array dynamically (At least i though so). I would also like to only be able to pass keys of Type T to the columns parameter. Therefore getting rid of the generics is not an option here. I also used the Extract type in order to render the columns separately, but excluding it makes no difference.

function Table<T, Key extends keyof T>({
  data,
  columns,
}: {
  data: T[];
  columns: Extract<Key, string>[];
  }) { 
  
  return (
    <div>
      {data.map((row) => (
        <tr>
          {columns.map((col) => (
            <td>{row[col]}</td> //this is where the error appears
          ))}
        </tr>
      ))}
    </div>
  );
}

This will generate following error:

Type 'T[Extract<Key, string>]' is not assignable to type 'ReactNode'.
  Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactNode'.
    Type 'T[string]' is not assignable to type 'ReactNode'.
      Type 'T[string]' is not assignable to type 'ReactPortal'.
        Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactPortal'.
          Type 'T[Extract<Key, string>]' is not assignable to type 'ReactPortal'.
            Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactPortal'.
              Type 'T[string]' is not assignable to type 'ReactPortal'.ts(2322)

In order to isolate the error i tried to reproduce the error using simple dynamic indexing and generic constraints:

function getKeyOfT<T, Key extends keyof T>(array: T[], key: Key) {
  return array[key];
}

Following error is generated:

Type 'keyof T' cannot be used to index type 'T[]'.ts(2536)

I have already looked at several answers, but they seemed to be different and their solutions did not seem to cover my issue:

As some of them suggested, asserting the type should solve the issue. However this seems to be redundant in this case:

function getElementOfArray<T, Key extends keyof T>(array: T[], key: Key) {
  return array[key as keyof T];
} 

CodePudding user response:

When you tried to isolate the error, the error message changed because it is a different error.

To solve your original error:

Type 'T[Extract<Key, string>]' is not assignable to type 'ReactNode'

This just means that TypeScript does not know what kind of content is inside T but it expects something assignable to ReactNode.

I would try to modify the definition of your function to:

function Table<T extends Record<string, ReactNode>, Key extends keyof T>({
  data,
  columns,
}: {
  data: T[];
  columns: Extract<Key, string>[];
  }) { 
  
  return (
    <div>
      {data.map((row) => (
        <tr>
          {columns.map((col) => (
            <td>{row[col]}</td> //this is where the error appears
          ))}
        </tr>
      ))}
    </div>
  );
}
  • Related