Самый простой способ для этого - для TableHeadCell<T>
быть типом union с одним членом для каждого K
в keyof T
. Один из способов добиться этого - создать сопоставленный тип, в котором каждое свойство соответствует каждому K
, а затем получить объединение этих свойств:
type TableHeadCell<T> = { [K in keyof T]: {
key: K;
label: string;
formatter?: (cell: T[K], row?: T) => string;
} }[keyof T];
Теперь вы можете написать следующее без ошибок:
const myTHeadCell1: TableHeadCell<Product> = {
key: 'article',
label: 'Article',
formatter(cell: string, row?: Product): string { return "" }
}
const myTHeadCell2: TableHeadCell<Product> = {
key: 'quantity',
label: 'Article',
formatter(cell: number, row?: Product): string { return "" }
};
Компилятор даже запомнит, что myTHeadCell1.formatter()
принимает параметр string
, а myTHeadCell2.formatter()
принимает number
, поскольку анализ типа потока управления временно сузит тип объединенное значение, основанное на присваивании:
if (myTHeadCell1.formatter) {
myTHeadCell1.formatter(""); // okay
myTHeadCell1.formatter(123); // error
}
if (myTHeadCell2.formatter) {
myTHeadCell2.formatter(""); // error
myTHeadCell2.formatter(123); // okay
}
Обратите внимание, что я изменил реализации средства форматирования, чтобы row
был необязательным. Это необходимо, чтобы соответствовать определению TableHeadCell<T>
. Если вы хотите, чтобы параметр row
был обязательным в реализации, он должен быть обязательным для аннотированного типа, потому что вам должно быть разрешено вызывать TableHeadCell<T>.formatter!()
с одним аргументом в соответствии с определением. (Убедитесь, что вы понимаете различие между типом функции с необязательными параметрами и реализацией функции, которая игнорирует дополнительные параметры, как описано в FAQ по TypeScript ).
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код