A versatile sorting algorithm

Currently, I am working on converting the material UI sorting feature into a generic type. This will enable me to utilize it across various tables. However, I have hit a roadblock in implementing the stableSort function, which relies on the getSorting function.

Understanding 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);

Exploring 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]);
};

Below is an example of how these functions are utilized:

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))
}

Main issues faced:

  1. The comparison

    props.defaultOrderBy === property
    consistently returns false. While both are of type keyof T, they are generically defined and should not have matching values. You can view a simplified version of this issue in the typescript playground.

  2. An error arises during the invocation of the stableSort function. (This has been resolved, refer to my solution below)

For more information, access the playground link here

Answer №1

There is a solution to problem one

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 the initial code,

someFunction = <T>(property: keyof T)
causes TypeScript to lose reference to the outer generic variable T. By changing the inner function to <P>(property: keyof T), we ensure that there is overlap and maintain the generic reference.

To allow for flexibility in recognizing key types of T, you can update the function as follows:

const someFunction = <P>(property: keyof T | string): boolean => ...

This change allows P to be either a key of the outer props or a string, providing more versatility in typing definitions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Add a class to a button in an Angular btn-group if a specific string is found within an

I am currently working on a project where I have multiple buttons that need to toggle an active class when selected in order to change their color. Below is a snippet of what I have: In the array called 'selected', I have: this.selected = [&ap ...

Dynamic Angular Menu

Is there a cleaner, more dynamic way to implement a mat menu with individual click values and disable properties for each button? I want to avoid repeating code like in the example below. Looking for a more dynamic solution. #code <mat-menu #createDeal ...

Add a class individually for each element when the mouse enters the event

How can I apply the (.fill) class to each child element when hovering over them individually? I tried writing this code in TypeScript and added a mouseenter event, but upon opening the file, the .fill class is already applied to all elements. Why is this ...

a guide on accessing key value elements within an array using Ionic 3

Just diving into the world of Ionic, I am currently working on a task to showcase products on the cart page that have been added to the cart. Upon fetching data from a REST API, I can see the response below in the console. "items": { "29.2.2.0.YTowOnt ...

Angular, perplexed by the output displayed in the console

I'm completely new to Angular and feeling a bit lost when it comes to the console output of an Angular app. Let me show you what I've been working on so far! app.component.ts import { Component } from '@angular/core'; @Component({ ...

Enrich your TypeScript code by unleashing the power of enum typing in overloading logical

I have a custom enum called PathDirection that represents different directions export enum PathDirection { LEFT="LEFT"; RIGHT="RIGHT"; }; Within my code, I need to toggle between the two directions. For example: let currentDire ...

Is there a method to improve type inference in vscode?

Recently, I created a component with a click handler that looks like this: onClick={(e) => { e.stopPropagation(); }} It seems clear to me, but then the Typescript compiler complains that it's not a valid signature for onClick, which actually a ...

Why is TypeScript resorting to using 'any' for specific prop type definitions in React?

Having some trouble with my props typing: export interface ITouchable { isDisabled?: boolean; margin?: Margin; height?: number; bgColor?: string; } The definition of Margin is as follows: type Margin = | { top?: number; bottom?: nu ...

Error: JSON parse error - unexpected character 'a' at index 1

I'm encountering an issue while attempting to change the album title from "cars" to "car". The error message I keep receiving is: SyntaxError: Unexpected token a in JSON at position 1. Any ideas on what might be causing this problem? Below is the cu ...

Getting the value of the chosen option from one component and passing it to another component in Angular 8

How can I pass the selected option value from the login component to the home component without using local storage? When an option is selected in the login component, I want that value to be displayed in the home component. Below is the code snippet: Lo ...

Exploring the World of Popper.js Modifiers

Within our React and Typescript application, we integrate the react-datepicker library, which utilizes popper.js. Attempting to configure PopperModifiers according to the example provided here: . Despite replicating the exact setup from the example, a typ ...

Mono repo project utilizing Angular 4+ and Typescript, enhanced with Bootstrap styling

Looking for a project to practice with Angular 4+ using Typescript and a Bootstrap template. Hoping for a setup where I can just run npm install and ng serve to start. Any recommendations for mono repos would be highly valued! ...

After updating the file path, the Next.Js module couldn't be located: Module not found – Unable to

After relocating the EmptyTable.tsx file from its original directory at views/forms-tables/tables/react-table/EmptyTable to a new location at components/Tables/EmptyTable, I encountered a persistent issue. Despite updating the import path in my code to mat ...

When executing prisma generate, an error of TypeError is thrown stating that the collection is

While using typescript with Prisma, I encountered an issue when trying to run prisma generate, as it kept throwing the following error: TypeError: collection is not iterable. at keyBy (/node_modules/@prisma/client/generator-build/index.js:57685:21) at ...

Declaration files for Typescript ESLint configurations

I've been researching this issue online, but I haven't been able to find any solutions. It could be because I'm not entirely sure what's causing the problem. What I'm trying to do is set a global value on the Node.js global object ...

What is the method for retrieving an attribute's value from an object that does not have key-value pairs?

My current project involves working with dynamoose and running a query that produces the following output: [ Document { cost: 100 }, lastKey: undefined, count: 1, queriedCount: undefined, timesQueried: 1 ] When I use typeof(output), it returns O ...

Utility managing various asynchronous tasks through observables and signaling mechanism

Looking for a Signal-based utility to monitor the status of multiple asynchronous operations carried out with observables (such as HTTP calls). This will enable using those signals in Components that utilize the OnPush change detection strategy. Imagine h ...

RXJS - Hold off until the shop is fully stocked

Here's a function I have that needs some adjustment: combineLatest([this.contact$, this.account$]).pipe( map((res) => {contacts = res[0], account = res[1]})).subscribe() I am facing an issue where the contact$ selector is sometimes empty. If it ...

Eliminate attributes from an object that are not defined within a specific type interface

I am trying to filter out properties from an object that are not defined in a specific type interface. Suppose I have the following interface: export interface CreateCustomerUserInput { fullname: string; email: string; } And this is my initial o ...

Iterate through an array containing objects that may have optional properties, ensuring to loop through the entire

I need help iterating through an array of objects with a specific interface structure: export interface Incident { ID: string; userName1?: string; userName2?: string; userPhoneNumber?: string; crashSeverity: number; crashTime: number; } Here ...