Giving the function parameter dynamic type depending on the first parameter

Currently, I have a basic function that my client uses to communicate with my server. In order to maintain flexibility, I have implemented the following:

public call(method: string, ...parameters: any[]) {}

On the server side, I organize all methods together like this:

MethodManager.methods({
    findOne: {
        function: function(collection: string, query: Object) {
            return model(collection).findOne(query).exec();
        }
    },
    find: {
        function: function(collection: string, query: Object, sortQuery: Object = {}) {
            return model(collection).find(query).sort(sortQuery).exec();
        }
    }
}

Each method has different parameters. Unfortunately, using 'any' as parameter type limits the use of Typescript in the client-side code.

Is there a way to configure Visual Studio Code to provide suggestions based on the specific method being called? For example, when typing:

this.socketManager.call('findOne', 

I would like it to suggest the following:

(method: 'findOne', collection: string, query: Object)

And for:

this.socketManager.call('find',

The suggestion should be:

(method: 'find', collection: string, query: Object, sortQuery: Object = {})

Instead of the generic:

(method: string, ...parameters: any[])

This enhancement would greatly improve the development process.

Answer №1

Dealing with a similar scenario, I encountered the need to trigger an event upon user login and logout. In my case, I aimed to create a function called sendEvent which required the userId payload object as mandatory if the login type was 'LOG_IN'. Conversely, this payload could be optional for 'LOG_OUT' events.

export type Event = { type: 'LOG_IN'; payload: { userId: string } } | { type: 'LOG_OUT' };

const sendEvent = <Type extends Event['type']>(
  ...args: Extract<Event, { type: Type }> extends { payload: infer TPayload } ? [type: Type,payload: TPayload] : [Type]
) => {
  // Send event stuff

};

sendEvent('LOG_IN', {userId: 'id1'})
sendEvent('LOG_OUT');

Answer №2

To implement function overloads in Typescript, you can structure your code like this: https://www.typescriptlang.org/docs/handbook/functions.html

For a more practical example, check out an illustrative instance:

function call(method: "find", collection: string, query: object): object;
function call(method: "findOne", collection: string, query: object, sortQuery: object): object[];
function call(method: "find" | "findOne", ...parameters: any[]): any {
    switch (method) {
        case "find": {
            const [collection, query] = parameters
            return {}
        }
        case "findOne": {
            const [collection, query, sortQuery] = parameters
            return [{}]
        }

    }
}

call("find", "collection", {})
call("findOne", "collection", {}, {})

call("find", "collection", {}, {}) // Error
call("findOne", "collection", {}) // Error

Answer №3

Through the use of a customized script, I successfully implemented a method to inspect all method files, extract functions and parameters, and regenerate a methods.ts file on the client side upon server code compilation. This script is designed to detect changes in the server code and update the client accordingly.

export function SERVER_METHODS(socketManager) {
    return {
        findOne: (collection: string, query: Object, cb?: Function)  => {
            socketManager.call('findOne', collection, query, cb);
        },
        find: (collection: string, query: Object, sortQuery: Object = {}, cb?: Function)  => {
            socketManager.call('find', collection, query, sortQuery, cb);
        },
        ...
    };
}

Subsequently, I leverage this approach by referencing it as follows:

public methods = SERVER_METHODS(this);

This enables me to streamline my code from conventional calls like:

this.socketManager.call('findOne', ...)

to more structured calls such as:

this.socketManager.methods.findOne(

With this setup, I am able to easily extract the required parameters for each function, despite the manual nature of the solution initially, the process has now been automated and proves effective.

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

Hiding the header on a specific route in Angular 6

Attempting to hide the header for only one specific route Imagine having three different routes: route1, route2, and route3. In this scenario, there is a component named app-header. The goal is to make sure that the app-header component is hidden when t ...

Having difficulty authenticating Slack requests

I'm currently working on a project to develop a Slack bot using the events API for an experiment at my job. I am facing challenges in verifying the request and can't seem to pinpoint where I'm making a mistake. The bot is being built using ...

Arranging a list of objects in Angular 6

I am facing difficulties in sorting an array of objects The structure of the object is as follows: My goal is to sort the *ngFor loop based on the group_id property. component.html <ul *ngFor="let list of selectgid | groupid"> <li>{{li ...

Comparing plain objects and class instances for modeling data objects

What is the recommended approach for creating model objects in Angular using TypeScript? Is it advisable to use type annotation with object notation (where objects are plain instances of Object)? For example, let m: MyModel = { name: 'foo' } ...

The 'Event' type is lacking the specified properties when compared to the 'CdkDragDrop<string[], string[]>' type

After exploring the reorderable columns demo on stackblitz, I came across this interesting code snippet. Specifically, here is the HTML snippet: <table mat-table [dataSource]="dataSource" cdkDropList cdkDropListOrientati ...

Module logo.svg not found? Error in Typescript

Integrating package: vue-svg-loader. Established the file svg.d.ts with the content below: declare module '*.svg' { const content: any export default content } Utilizing it in a component in the following manner: import register from &apo ...

Guide to accessing a newly opened window from a different domain originating from the current window

Currently working on an Angular project, I am facing a scenario where I have a link on page A that directs users to a different origin page B. The HTML code for the link is shown below: ... <a href="https://another.origin"> PAGE B </a> ... On ...

Extract keys from a list of interface keys to create a sub-list based on the type of value

Issue Can the keys that map to a specified value type be extracted from a TypeScript interface treated as a map? For example, consider the WindowEventMap in lib.dom.d.ts... interface WindowEventMap extends GlobalEventHandlersEventMap, WindowEventHan ...

Bar chart in Chart.js becomes crowded and illegible on smaller screens due to overlapping bars

Hello there! I've encountered an issue where the bar chart overlaps when the screen width is too low. It seems to be related to the maintainAspectRatio property, which I set to false because I wanted the charts to shrink only in width, not in both axe ...

Leveraging NPM workspaces in combination with Expo and Typescript

I'm struggling to incorporate NPM 7 workspaces into a Typescript Expo project. The goal is to maintain the standard Expo structure, with the root App.tsx file, while segregating certain code sections into workspaces. I'm facing challenges compil ...

What is the best way to incorporate ControlContainer in an Angular component's unit test?

Is there a way to include ControlContainer in an Angular unit test? The error message I am encountering reads: NullInjectorError: StaticInjectorError(DynamicTestModule)[ChildFormComponent -> ControlContainer]: StaticInjectorError(Platform: core) ...

How do I condense nested keys in TypeScript?

If I have two types defined in TypeScript: interface Foo { bar: string; } interface Baz { foo: Foo; } Is it possible to flatten the Baz type in TypeScript (e.g. type FlatBaz = Flatten<Baz>), so that the signature appears similar to this? inte ...

I'm confused by the function: "sort((a: Article, b: Article) => b.votes - a.votes);"

I'm having trouble grasping the concept of the return statement in sortedArticles(). Can anyone provide me with a resource or explain how this sorting function works? sortedArticles(): Article[] { return this.articles.sort((a: Article, b: Article ...

A guide to effectively converting and parsing a class object that includes Uint8Array elements

After stringifying a class object that contains a property in Uint8Array, and then parsing it later, the property is no longer in Uint8Array format. Here's an example: class Example { title:string; byteData:Uint8Array; ...

Combining arrays using Observables in Typescript with RxJS

Having some issues using rxjs Observable.concat function in typescript. Encountering an error "Cannot read property 'apply' of undefined" The problem appears to be limited to typescript and may be related to rxjs version 5 concat. The code seems ...

What causes the error message saying 'undefined' cannot be assigned to the specified type ...?

I just finished developing an innovative Angular application. Within the app.component.html file, I have included: <bryntum-scheduler #scheduler [resources] = "resources" [events] = "events" [columns] = "schedul ...

What is the proper method for utilizing a conditional header in an rtk query?

How can I implement conditional header authentication using rtk query? I need to pass headers for all requests except refresh token, where headers should be empty. Is it possible to achieve this by setting a condition or using two separate fetchBaseQuery ...

Authentic property does not reveal its contents

Currently, I am utilizing Angular2 and my goal is to only display a component if a certain property is true. The issue arises when trying to show the <sci-company-form> element when the sci variable is set to true. When setting public sci: boolean = ...

Retrieve all items that match the ids in the array from the database

I'm having trouble receiving a list of items that match with my array of ids. Here's a snippet from the Angular component code: this.orderService.getSpecyficOrders(ids) .subscribe(orders => { ... Where ids is an array of [{_id : ID }, ...

The Static Interface Binding in TypeScript

I have inquired about how to extend the static functionality of existing objects in JavaScript (using TypeScript). In all examples provided here, I am utilizing Object The code below showcases a polyfill definition for ECMAScript's Object.is function ...