I am trying to make the material UI sorting function into a generic typed. So that I can use it with any kind of table. I am stuck at using stableSort
function, which uses getSorting
function.
stableSort:
const getSorting = <K extends keyof any>(
order: Order,
orderBy: K,
): (a: { [key in K]: number | string }, b: { [key in K]: number | string }) => number =>
order === "desc" ? (a, b) => desc(a, b, orderBy) : (a, b) => -desc(a, b, orderBy);
getSorting:
const stableSort = <T>(array: T[], cmp: (a: T, b: T) => number): T[] => {
const stabilizedThis = array.map((el, index) => [el, index] as [T, number]);
stabilizedThis.sort((a, b) => {
const order = cmp(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
};
And thats how I am using the functions,
interface ITableProps<T> {
title: string;
rows: T[];
defaultOrderBy: keyof T;
order: Order;
}
const SomeTable = <T>(props: ITableProps<T>) => {
const rowsPerPage = 10;
const page = 0;
const handleRequestSort = <T>(property: keyof T): void => {
const isDesc = props.defaultOrderBy === property && props.order === "desc";
};
const sortingFunction = getSorting<keyof T>(props.order, props.defaultOrderBy);
const temp = stableSort<T>(props.rows, sortingFunction)
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => createTableRow(row, index))
}
Couple of problems I am facing,
I dont understand why it thinks props.defaultOrderBy === property
will always be false
. I know that both are keyof T
, but thats a generic type, and their values will not be the same. Small contained replication of this problem in playground
I have a compilation error when calling stableSort
function. (Solved, check my answer below)
Problem one can be resolved this was
interface ISomeComponentProps<T> {
firstValue: keyof T;
secondValue: keyof T;
}
const SomeComponent = <T>(props: ISomeComponentProps<T>): void => {
const someFunction = <P>(property: keyof T): boolean => {
return props.firstValue === property;
};
const temp = someFunction(props.secondValue);
}
In your previous code you were using someFunction = <T>(property: keyof T)
That causes typescript to lose its reference to the outer generic T
since they are the same generic variable. By switching the inside function to <P>(property: keyof T)
we are saying that the inside is a generic function that must take as its property a keyof the outside function. That is the only way to ensure that there will be overlap is by typing it so that there must be.
You can also tell TS that it may be a key of T but not necessarily by typing it this way
const someFunction = <P>(property: keyof T | string): boolean => ...
Now you are saying that P
is either a keyof
the outside props
or a string. Obviously you can replace string with whatever other values you might have there.