I want to sort an array of object (of the same interface) firstly sorting by one attribute of this interface, if these attributes are equals then sorting by secondly attribute, then sorting by a third attribute and so on. And all in typescript mode.
My attempt solutions:
Define the sorter:
type Sorter = (a: T, b: T) => number;
Example:
const stateSorter = (aState: number, bState: number) => (bState < aState? -1 : 1);
const dateSorter = (aDate: Date, bDate: Date) => (aDate >= bDate ? -1 : 1);
Define a sorter around attribute of a interface T
interface SortSupplier<T, R> { supplier: (container: T) => R; sorter: Sorter< R >; }
Example:
interface StateAndDate {
stateId: ClientStateIdEnum;
registrationDate: Date;
}
const sorterBySupplier: SortSupplier<StateAndDate, Date> = {supplier: container => container.registrationDate, sorter: dateSorter}
First incorrect attempt:
Do by array of priority sort of SortSupplier:
const sortBySorters1 = <T>(a: T, b: T, orderedSorters: SortSupplier<T, any>[]): number => {
let sortResult = 0;
orderedSorters.some(supplierSorter => {
sortResult = supplierSorter.sorter(supplierSorter.supplier(a), supplierSorter.supplier(b));
return sortResult !== 0;
});
return sortResult;
}
and one wrong example is:
(a: StateAndDate, b: StateAndDate) => {
return sortBySorters1(a, b, [
{supplier: container => container.stateId, sorter: stateSorter},
{supplier: container => container.registrationDate, sorter: stateSorter}
]);
}
It is wrong because the second sorter must sort by date but it accepts other different sorter, by number (state), due to the use of any as the second generic type of the SortSupplier
Second incorrect attempt:
Create a type of all possible attributes types of SortSupplier, for example, numbers and dates:
type SortSupplierType<T> = SortSupplier<T, Date>|SortSupplier<T, number>;
Then the previous incorrect sorter configuration:
{supplier: container => container.registrationDate, sorter: stateSorter}
gives compilation error and the only compliance solution is the rigth one:
(a: StateAndDate, b: StateAndDate) => {
return sortBySorters1(a, b, [
{supplier: container => container.stateId, sorter: stateSorter},
{supplier: container => container.registrationDate, sorter: dateSorter}
]);
}
But:
const sortBySorters2 = <T>(a: T, b: T, orderedSorters: SortSupplierType<T>[]): number => {
let sortResult = 0;
orderedSorters.some(supplierSorter => {
sortResult = supplierSorter.sorter(supplierSorter.supplier(a), supplierSorter.supplier(b));
return sortResult !== 0;
});
return sortResult;
}
But it gives the next compilation error:
Argument of type 'number | Date' is not assignable to parameter of type 'Date & number'.
Type 'number' is not assignable to type 'Date & number'.
Type 'number' is not assignable to type 'Date'.
sortResult = supplierSorter.sorter(supplierSorter.supplier(a), supplierSorter.supplier(b));
¿Someone has a generalized solution to this sort problem around cascading priorioty sort of attributes interface?
(Sorry for my English)