typescript: шаблонная функция в которой в качестве параметра выступает название поля объекта
у меня есть множество однотипных функций для сортировки, которые передаются фреймворку, отрисовывающему таблицы и сортирующему поля (Ant Desgin) и отличающуюся названием полей и типом данных:
sorter: (a: IType1, b: IType1) => (a.created_at ?? 0) - (b.created_at ?? 0),
хочется вместо кода сравнения двух значений указывать какую-то более короткую запись, не зависящую от типа данных, что-то типа
sorter: my_sorter,
Если написать функцию
function my_sorter(a: IType1, b: IType1) {
return (a.created_at ?? 0) - (b.created_at ?? 0);
}
То это то, что надо за исключением 2х вещей - одна применима только для заданного типа и заданного названия поля, а хотелось бы указывать функцию и дополнительно указывать поля и типы данных (если нужно), что-то типа
sorter: my_sorter<IType1.created_at>,
Можно ли это реализовать в typescript?
P.S.
Не очень бы хотелось указывать поля в виде строк и т.д., т.е. легко можно написать функцию, чтобы делать так:
sorter: (a: IType1, b: IType1) => my_sorter(a, b, 'created_at'),
Но это уже как-то менее эстетично :(
Ответы (1 шт):
Для реализации функции сортировки которая будет принимать ключ и возвращать отсортированный массив можно воспользоваться типом который отсечёт все лишние ключи не содержащие число и сделать функцию с замыканием которая будет принимать тот самый ключ и возвращать результат для функции sort
Рабочий пример: typescriptlang.org
type NumericKeys<T> = {
[K in keyof T]: T[K] extends number ? K : never;
}[keyof T];
function compareByKey<T extends object>(key: NumericKeys<T>, customValidation?: (a: number, b: number) => number) {
return (a: T, b: T) => {
if (customValidation) {
return customValidation(Number(a[key]), Number(b[key]));
} else {
return Number(a[key]) - Number(b[key]);
}
};
}
//
interface User {
name: string;
created_at: number;
}
interface Car {
id: number;
model: string;
}
const users: User[] = [
{ name: 'test 1', created_at: 1 },
{ name: 'test 2', created_at: 2 },
{ name: 'test 3', created_at: 3 },
];
const cars: Car[] = [
{ id: 1, model: 'test 1' },
{ id: 2, model: 'test 2' },
{ id: 3, model: 'test 3' },
];
users.sort(compareByKey<User>('created_at')); // [1, 2, 3]
users.sort(compareByKey<User>('created_at', (a, b) => (b - a))); // [3, 2, 1]
cars.sort(compareByKey<Car>('id')); // [1, 2, 3]
cars.sort(compareByKey<Car>('id', (a, b) => (b - a))); // [3, 2, 1]