Типизация значений через дженерики

Я не знаю как правильнее описать то, что я имею ввиду.

Мне нужен такой интерфейс (в текущей реализации это не работает), но с тем дополнением, что я хочу добавить дополнительные значения для id, но в таком случае для value должен быть тип unknown

interface IColumn<T extends object, AdditionalKeys extends string = never, U = keyof (T & Record<AdditionalKeys, any>)>
{
  id: U;
  format(value: T[U]): any;
}

Ожидаемое поведение:

interface IColumn<T extends object, AdditionalKeys extends string = never, U = keyof (T & Record<AdditionalKeys, any>)>
{
  id: U;
  format(value: T[U]): any;
}

interface ITest
{
  key1: number;
  key2: string;
  key3: Date;
}

const columns: IColumn<ITest, "test">[] = [
  {
    id: "key1",
    format(value) // должен быть тип number
    {
      return value;
    }
  },
  {
    id: "key2",
    format(value) // должен быть тип string
    {
      return value;
    }
  },
  {
    id: "key3",
    format(value) // должен быть тип Date
    {
      return value;
    }
  },
  {
    id: "test",
    format(value) // должен быть тип unknown
    {
      return value;
    }
  },
  {
    id: "another", // Должна быть ошибка
    format(value)
    {
      return value;
    }
  }
]

TypeScript Playground


Ответы (1 шт):

Автор решения: nörbörnën

Types:

type IColumn<S extends Record<string, any>, ADD extends string = never> = ({
  [K in (keyof S) | ADD]: {
    id: K;
    format(value: K extends (keyof S) ? S[K] : unknown): any;
  };
})[(keyof S) | ADD];

interface ITest {
  key1: number;
  key2: string;
  key3: Date;
}

type TColumnsTest = IColumn<ITest, 'test'>[];

Result:

type TColumnsTest = ({
    id: "test";
    format(value: unknown): any;
} | {
    id: "key1";
    format(value: number): any;
} | {
    id: "key2";
    format(value: string): any;
} | {
    id: "key3";
    format(value: Date): any;
})[]

Usage example:

const columns = [
  ...
] as const satisfies TColumnsTest;
→ Ссылка