Skip to content

Conversation

@Smona
Copy link

@Smona Smona commented Apr 25, 2025

Fixes #4382

I ran into #4382 trying to write a generic, reusable wrapper around react-table. Looking into the issue brought me to the ColumnHelper type. I've had issues in the past when trying to transform one generic type parameter into a second, inferred generic parameter, and often it can be fixed using a distributive helper type instead. So I tried pulling out the TValue generic parameter into one, and then using that in ColumnHelper instead.

This seems to work! I'm able to create a properly typed, generic reusable wrapper component by defining the props like this:

type Columns<T> = {
    [K in keyof Required<T>]: ColumnDef<T, T[K]>;
}[keyof Required<T>][];
type ColumnsBuilder<T> = (helper: ColumnHelper<T>) => Columns<T>;

interface Props<T> {
  data: T[] | null;
  columns: ColumnsBuilder<T>;
};

And the types are compatible, with no types lost:

type Person = {
    id: number;
    firstName: string;
    lastName: string;
    age?: number;
    visits: number;
    status: string;
};

// (ColumnDef<Person, number> | ColumnDef<Person, string> | ColumnDef<Person, number | undefined>)[]
type ColumnsType = Columns<Person>;

const columns: ColumnsBuilder<Person> = (columnHelper) => [
    // Inferred as: <(p: Person) => string>(accessor: (p: Person) => string, column: DisplayColumnDef<Person, string>) => AccessorFnColumnDef<Person, string>
    columnHelper.accessor((p) => p.firstName, {
        header: 'First Name',
        cell: (info) => <strong>{info.getValue()}</strong>,
    }),
    // inferred as: <"age">(accessor: "age", column: IdentifiedColumnDef<Person, number | undefined>) => AccessorKeyColumnDef<Person, number | undefined>
    columnHelper.accessor('age', {
        header: 'Last Name',
        cell: (info) => <em>{info.getValue()}</em>,
    }),
    // inferred as: <"status">(accessor: "status", column: IdentifiedColumnDef<Person, string>) => AccessorKeyColumnDef<Person, string>
    columnHelper.accessor('status', {
        header: 'Status',
        cell: (info) => (
            <span
                style={{
                    color: info.getValue() === 'Active' ? 'green' : 'red',
                    fontWeight: 'bold',
                }}
            >
                {info.getValue()}
            </span>
        ),
    }),
],

@Smona
Copy link
Author

Smona commented Oct 23, 2025

@KevinVandy any changes you would like to see here? we've been using this type in our codebase for a while now without issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ColumnDef types gives typescript error

1 participant