Billy Bones
Billy Bones

Reputation: 2965

TypeScript w/ React - Argument of type 'string' is not assignable to parameter of type 'keyof T'

I have a sorting function built with TypeScript and React Hooks that I am having some issues with.

Specifically I am receiving an error stating:

Argument of type 'string' is not assignable to parameter of type 'keyof T'.
  Type 'string' is not assignable to type 'never'.ts(2345)

You can see the sorting function and how I am attempting to test it here on CodeSandbox

I am not really sure where the never would be coming from.

Any helpful links would be appreciated.

I will try to remove some of the unnecessary code but I have a bad habit of removing code which then changes the context (when using TypeScript) which results in a answer that may not be as helpful for my use case.

import { useState, useEffect } from "react";

export function SortByKey<T extends object>({
  data,
  sortKey
}: {
  data: T[];
  sortKey: keyof T;
}) {
  let sortable = [...data];

  sortable.sort((a: T, b: T) => {
    if (a[sortKey] < b[sortKey]) {
      return -1;
    }
    if (a[sortKey] > b[sortKey]) {
      return 1;
    }
    return 0;
  });

  return sortable;
}

export default function App<T extends object>({ data }: { data: T[] }) {
  const [sortedData, setSortedData] = useState(data);

  const sortKeys: string[] = Object.keys(data[0]);

  function handleClick(sortKey: keyof T) {
    setSortedData(SortByKey({ data, sortKey }));
  }

  useEffect(() => {
    console.log(sortedData);
  }, [sortedData]);

  return (
    <div>
      {sortKeys.map((sortKey) => {
        return (
          <button key={sortKey} onClick={() => handleClick(sortKey)}>
            {sortKey}
          </button>
        );
      })}
    </div>
  );
}

Upvotes: 4

Views: 4770

Answers (2)

c69
c69

Reputation: 21507

Replace object in "App<T extends object>" with Record<string, any>, ie:

export default function App<T extends Record<string, any>>({ data }: { data: T[] }) {

this will make handleClick of button.onClick stop throwing errors.

Why: because when you ask for keys of object, they are empty by default, and there is no index signature as well.

Upvotes: 4

Ibraheem
Ibraheem

Reputation: 2358

You need to cast sortKeys to (keyof T)[]:

const sortKeys = Object.keys(data[0]) as (keyof T)[];

But it doesn't look like a very useful type.

Upvotes: 2

Related Questions