Developing an object using class and generic features in Typescript

I am currently working on creating a function or method that can generate sorting options from an array. One example is when using Mikro-ORM, where there is a type called FindOptions<T> that can be filled with the desired sorting order for database queries.

The FindOptions interface is defined as:

export interface FindOptions<T, P extends string = never> {
    populate?: readonly AutoPath<T, P>[] | boolean;
    orderBy?: (QueryOrderMap<T> & {
        0?: never;
    }) | QueryOrderMap<T>[];
    limit?: number;
    offset?: number;
    ...
}

When directly interacting with FindOptions, I can specify my Entity as the generic

const MikroORMSoryBy: FindOptions<TimeEntryEntity>
, which provides code completion and compiler hints.

To set up my sort by fields, I would do the following:

const MikroORMSoryBy: FindOptions<TimeEntryEntity> = {
    orderBy: { EntryDate: QueryOrder.ASC, Id: QueryOrder.ASC, UserId: QueryOrder.ASC }
};

I am able to list my fields without any issues, even as strings within the object.

orderBy: { 'EntryDate': QueryOrder.ASC, 'Id': QueryOrder >ASC, 'UserId': QueryOrder ASC }

My question is, how can I dynamically build the orderBy object based on input provided in an array, rather than hardcoding the field names? This would allow me to create a reusable function for generating sorting options.

What I ideally want to achieve is something like the following:

const Fields: Array<string> = ['EntryDate', 'Id', 'UserId'];
Fields.forEach( (OneField: string) => {
    orderBy[OneField] = QueryOption.ASC;  // ???
});

Answer №1

To begin, let's create a new function that accepts two generic parameters:

function generateOrder<T, Keys extends (keyof T)[]>(keys: [...Keys]) => {
    return keys.reduce((result, key) => ({ ...result, [key]: OrderType.ASC }), {} as { [K in Keys[number]]: OrderType });
}

In simple terms, this function takes the keys of an entity and forms an object with those keys mapped to OrderType.ASC.

However, when attempting to use it like so:

const orderGenerator = generateOrder<MyEntity>([...]);

An error occurs because we haven't supplied the generic parameter Keys. If we do provide it, we end up duplicating the input to the function, which is undesirable. This issue is known as partial type inference, and one solution is to employ currying:

function generateOrder<T>() {
    return <Keys extends (keyof T)[]>(keys: [...Keys]) => {
        return keys.reduce((result, key) => ({ ...result, [key]: OrderType.ASC }), {} as { [K in Keys[number]]: OrderType });
    };
}

Now we can utilize it in this manner:

const order = generateOrder<MyEntity>()([...]);

This approach may be more practical as you can store the intermediate function:

const order = generateOrder<MyEntity>();

order([...]); // use independently

Interactive Example

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

The response of the Typescript Subscription function

I'm struggling with retrieving the subscribe array in NG2. Being new to typescript, I find it difficult to understand how to pass variables between functions and constructors. This is what my code currently looks like: export class RosterPage exten ...

Create a pipeable stream that does not trigger any events when data is piped

I have been trying to utilize the renderToPipeableStream function from React18, and although it is functional, I am struggling with handling the pipe properly. The key section of my code involves an array of strings representing HTML. I am splitting the s ...

Issue with Angular2/4 Module: Unable to locate 'three' in the application directory

As a newcomer to Angular and TypeScript, I am encountering difficulties when trying to import the @types/three npm package. I have created a new Angular project and attempted to use the three package, but I keep receiving the following error: Module not f ...

Error encountered during Typescript compilation in Angular9 using Babylon4.1.0 - Unable to locate 'react' module or namespace 'JSX' not found

I am currently encountering compilation issues with Babylon4.1.0 within an angular9 app. It appears that the inspector is having trouble importing the internally used "react" module. To reproduce the issue: * Create a new angular9 app using the CLI * Add @ ...

No response was forthcoming

I have been trying to send a post request to my login endpoint, but I am not receiving any response. Despite thoroughly checking my code, I am unable to figure out why there is no response being sent back. My backend is built using Express in TypeScript. B ...

Utilize generic typings to interact with the Array object

I'm facing a challenge in developing an interface that is dependent on another interface. Everything was going smoothly until I reached the Array of Objects. Let me elaborate, I have an 'Entity' that defines how a document is stored in a ...

"Encountering issues with Angular2's FormBuilder and accessing nested object properties,

As I dip my toes into TypeScript and Angular2, I find myself grappling with a nested object structure in an API. My goal is to align my model closely with the API resource. Here's how I've defined the "Inquiry" model in TypeScript: // inquiry.ts ...

Is the parent component not triggering the function properly?

Hey there, I'm working with the code snippet below in this component: <app-steps #appSteps [menuSteps]="steps" [currentComponent]="outlet?.component" (currentStepChange)="currentStep = $event"> <div appStep ...

Tips for organizing an NPM package containing essential tools

Currently facing the challenge of creating an NPM package to streamline common functionality across multiple frontend projects in our organization. However, I am uncertain about the correct approach. Our projects are built using Typescript, and it seems th ...

Exciting Update: Next.js V13 revalidate not triggering post router.push

Currently using Next.js version 13 for app routing, I've encountered an issue with the revalidate feature not triggering after a router.push call. Within my project, users have the ability to create blog posts on the /blog/create page. Once a post is ...

Could anyone provide an explanation for the statement "What does '[P in keyof O]: O[P];' signify?"

As a new Typescript user looking to build a passport strategy, I came across a line of code that has me completely baffled. The snippet is as follows: here. The type StrategyCreated<T, O = T & StrategyCreatedStatic> = { [P in keyof O]: O[P]; ...

Guide for launching Electron on a local host server during development and for production builds

I have a project using Next.js + Electron + Typescript. I used the npx create-next-app --example with-electron-typescript command to generate the initial code. When I run npm run dev (which actually runs npm run build-electron && electron . ), the ...

Unable to import necessary modules within my React TypeScript project

I am currently building a React/Express application with TypeScript. While I'm not very familiar with it, I've decided to use it to expand my knowledge. However, I've encountered an issue when trying to import one component into another comp ...

Merge arrays values with Object.assign function

I have a function that returns an object where the keys are strings and the values are arrays of strings: {"myType1": ["123"]} What I want to do is merge all the results it's returning. For example, if I have: {"myType1": ["123"]} {"myType2": ["45 ...

Struggling to modify a string within my React component when the state is updated

Having a string representing my file name passed to the react-csv CSVLink<> component, I initially define it as "my-data.csv". When trying to update it with data from an axios request, I realize I may not fully understand how these react components w ...

"TypeScript function returning a boolean value upon completion of a resolved promise

When working on a promise that returns a boolean in TypeScript, I encountered an error message that says: A 'get' accessor must return a value. The code snippet causing the issue is as follows: get tokenValid(): boolean { // Check if curre ...

The issue with launching a Node.js server in a production environment

I'm currently facing an issue when trying to start my TypeScript app after transpiling it to JavaScript. Here is my tsconfig: { "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "baseUrl": "src", "target": " ...

Enhance the MUI palette by incorporating TypeScript, allowing for seamless indexing through the palette

When utilizing the Material UI Palette with Typescript, I am encountering a significant issue due to limited documentation on MUI v5.0 in this area. Deep understanding of typescript is also required. The objective is to iterate through the palette and vir ...

What is the method for utilizing a class variable without assigning a value to it initially

class testClass { student: { name: string, age: number } constructor(options?: any) { this.student = { name: '', age: 0 }; } setStudent(name:string, age:number) { this.student.name ...

Is it possible to access the generic type that a different generic type inherits in TypeScript?

I've developed an interface specifically designed for types capable of self-converting to IDBKey: interface IDBValidKeyConvertible<TConvertedDBValidKey extends IDBValidKey> { convertToIDBValidKey: () => TConvertedDBValidKey; } My goal n ...