'Is there a way to have mapped type together with index signatures?

Consider example below

type Config<T> = {
  [K in keyof T]?: { render: (value: T[K]) => React.ReactNode };
};

type TableProps<T> = {
  data: T[];
  config: Config<T>;
};

const Table = <T,>(props: TableProps<T>) => {
  return <div>{/** */}</div>;
};

type Line = {
  name: string;
  age: number;
};

export const App = () => {
  const data = useMemo<Line[]>(() => [], []);

  return (
    <Table
      data={data}
      config={{
        age: { render: (value) => value },
        name: { render: (value) => value }
      }}
    />
  );
};

This works fine when I want to use keys of Line type for Config type. But is there a way to add other optional keys that does not belong to Line type. In the end I want the render method to know what type of value it receives upon creation of config object as a prop for Table

Case 1
As age and name are keys of Line render method knows value is string and number

      config={{
        age: { render: (value: number) => value },
        name: { render: (value: string) => value }
      }}

Case 2
I want to add properties that are not part of Line to config

      config={{
        age: { render: (value) => value },
        name: { render: (value) => value },
        randomProp: {render: (value: unknown) => /** do some transformation */}
      }}

To achieve Option 2 I need to change Config type to something else. I tried to do it like this but it doesn't work. Type for value is always unknown

type Config<T, P extends keyof T> = {
  [K in P | string]?: { render: (value: K extends keyof T ? T[K] : unknown) => React.ReactNode };
};

type TableProps<T, P extends keyof T> = {
  data: T[];
  config: Config<T, P>;
};

const Table = <T, P extends keyof T>(props: TableProps<T, P>) => {
  return <div>{/** */}</div>;
};

export const App = () => {
  const data = useMemo<Line[]>(() => [], []);

  return (
    <Table
      data={data}
      config={{
        age: { render: (value) => value },
        name: { render: (value) => value },
        randomProp: {render: (value: unknown) => /** do some transformation */}
      }}
    />
  );
};

Type '(value: number) => number' is not assignable to type '(value: unknown) => ReactNode'. Types of parameters 'value' and 'value' are incompatible. Type 'unknown' is not assignable to type 'number'.ts(2322)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source