Adapting the return type dynamically according to the input given

I have a set of 4 different classes:

class AddCommand {
   // TODO
}

class AddCommandOutput {
   // TODO
}

class RemoveCommand {
   // TODO
}

class RemoveCommandOutput {
   // TODO
}

I am currently working on creating a function that can take either AddCommand or RemoveCommand as an argument, and then return the corresponding AddCommandOutput or RemoveCommandOutput based on the input.

Initially, my function looked something like this:

function processCommand(command: AddCommand|RemoveCommand): AddCommandOutput|RemoveCommandOutput {
   // TODO:
}

However, I found myself needing to check the type of the return value after calling the function like this:

const result = processCommand(command);

if (result instanceof AddCommandOutput) {

} else {
   // RemoveCommandOutput
}

To enhance the intelligence of the function, I could potentially modify it to look like this:

function processCommand<T>(command: AddCommand|RemoveCommand): T {
   // TODO:
}

But even in this case, I would still have to specify the return type explicitly like so:

const result = processCommand<RemoveCommandOutput>(command);

Is there a way to further improve the function's intelligence by dynamically adjusting the return type based on the provided argument?

For example:

const result = processCommand(addCommand); // providing an instance of AddCommand so that the return type is AddCommandOutput

// With this, I should be able to access all the functions of AddCommandOutput

Answer №1

function processDirective<D extends AddDirective | RemoveDirective>(directive: D) 
    : D extends AddDirective ? AddDirectiveOutput : RemoveDirectiveOutput  {
       // TODO:
    }

I trust this guidance will be beneficial to you.

Answer №2

Unfortunately, due to limited information, this is the best solution available.

interface PutCommand {
  type: 'put';
  payload: any;
}

interface PostCommand {
  type: 'post';
  payload: any;
}

interface PutCommandOutput {
  type: 'put';
  body: any;
}

interface PostCommandOutput {
  type: 'post';
  body: any;
}

type ReturnCommandOutput<T> =
  T extends PutCommand ? PutCommandOutput :
  T extends PostCommand ? PostCommandOutput :
  never;

function executeCommand<T>(command: T): ReturnCommandOutput<T> {
  return {
    // ...
  } as ReturnCommandOutput<T>;
}

const putCommand: PutCommand = {
  type: 'put',
  payload: {}
}

const postCommand: PostCommand = {
  type: 'post',
  payload: {}
}

const putCommandOutput = executeCommand(putCommand);
const postCommandOutput = executeCommand(postCommand);

TS Playground ---> Here

https://i.sstatic.net/x3Wx0.png

https://i.sstatic.net/3o9SN.png

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

What is the best way to combine properties from Type1 and Type2 to create a new type in Typescript?

Here is a snippet of code I'm working with: interface Notification { message: TemplatedEmail & Email, //current attempt which doesnt do what I want } interface Destination { ccAddresses?: string[], bccAddresses?: string[], toAddresses: st ...

The global variable in TypeScript is not specified; it is initialized within the declaration `declare global{}`

In my TypeScript code, I'm facing a challenge when trying to add a global scope variable. In JavaScript (NodeJS), this process is straightforward: // index.js globalThis.helloWorld = 'Hello World!'; require('./log.js') // log.js c ...

Structuring a project with React and backend for sharing code

The organization of folders outlined in the structure below for a React frontend and Express backend is really appealing to me: root ├── backend | ├── node_modules | ├── public | ├── src │ │ └── Server.ts | ...

Issue: StaticInjectorError(DynamicTestModule)[CityService -> Http]: Http provider not found

I am working on a service that retrieves all cities from a web service. @Injectable() export class CityService { constructor(private http: Http, private router: Router, private auth: AuthService) { } public getAllCity(): Observable<City[]> { ...

Eliminate repeat entries in MongoDB database

Within our MongoDB collection, we have identified duplicate revisions pertaining to the same transaction. Our goal is to clean up this collection by retaining only the most recent revision for each transaction. I have devised a script that successfully re ...

Ionic 2: Issue with Custom Provider Resulting in "Unable to Resolve All Parameters"

I have created a test provider and I am attempting to inject it into two pages for the purpose of sharing data and methods. However, when I add the provider to the page constructor, an error is thrown, stating "Can't resolve all parameters for Charact ...

What is the best way to link together Angular observables?

In order for my component to make API requests, it needs to check if certain app preferences are set. Currently, I have implemented a method where the component's data is refreshed every 2 minutes using a timer: ngOnInit(): void { this.subscriptio ...

Using Angular to handle routes with a specific domain prefix

Let's say I own the domain https://example.com and I'd like to create a subdomain specifically for my blog, like this: https://blog.example.com. How would you handle the routing for this scenario using Angular? ...

Angular class requires multiple class members and validators for MatSelection List to be bound with Formbuilder

Could you please guide me on how to connect the Google Angular Materials mat-selection-list with the FormBuilder? We have the following class and are attempting to utilize Reactive Form Builder for this purpose. While we are aware of how to link data class ...

What is the best way to bring in the angular/http module?

Currently, I am creating an application in Visual Studio with the help of gulp and node. Node organizes all dependencies into a folder named node_modules. During the build process, gulp transfers these dependencies to a directory called libs within wwwroo ...

Unable to access structuredClone on the global object within a Node.js application

structuredClone is causing issues in my NodeJS application. Whenever I try to utilize it, I encounter the error: structuredClone is not defined nodejs. To troubleshoot, I created a simple file and executed the following: console.log({ globals: Object. ...

Guide on the correct way to develop a Typescript NPM package accompanied by declarations?

It feels like I'm struggling with a simple task that is driving me crazy. I have several TypeScript files with code that I want to export for an npm package. In order to enable auto-imports from npm packages, all function and constant types need to b ...

Is it possible to refresh the component view using the service?

I am interested in developing a NotificationService that will be utilized to showcase a notification from another section. My inquiry is, how can I refresh the view of a component using a service? My ultimate goal is to have the capability to embed a comp ...

Is there a way to customize the "instanceof" functionality for an ArrayBuffer?

I've been working on a project that involves using threejs to draw a filled polygon based on its vertices. Initially, I started with a square and was able to get it working perfectly on its own. However, the real issue arose when I tried to integrate ...

Webpack 4.1.1 -> The configuration.module contains a property 'loaders' that is unrecognized

After updating my webpack to version 4.1.1, I encountered an error when trying to run it: The configuration object is invalid. Webpack has been initialized with a configuration that does not match the API schema. - The 'loaders' property in ...

Angular 2 does not update the variable value within a dataservice call on the page until you navigate away from the page and then come back to it

Currently, I am working with Angular2 and have encountered a strange issue. I have a variable that I display on the page, and when a button is clicked, a data service is called to update the value of this variable. Surprisingly, even after changing the val ...

Webpack bundling only a singular Typescript file rather than all of its dependencies

I'm currently facing a challenge while attempting to consolidate all the files in my Typescript project, along with their dependencies from node_modules, into a single file using Webpack. Despite trying multiple options, it seems that only the entry f ...

redux-saga 'call' effect fails to properly type saga parameters

My saga is defined as follows: type GenericFunction = (...args: any[]) => any; interface IFetchSaga<T extends GenericFunction> { saga: T, args: Parameters<T> } function* triggerChange<T extends GenericFunction>(fetchSaga: IFetchS ...

Suggestions for managing the window authentication popup in Protractor when working with Cucumber and TypeScript?

I'm a beginner with Protractor and I'm working on a script that needs to handle a window authentication pop-up when clicking on an element. I need to pass my user id and password to access the web page. Can someone guide me on how to handle this ...

Struggling to create a SVG Line with DOM Manipulation in Typescript

I'm having trouble adding an SVG element to my div using the appendChild function in TypeScript. I want to add a line inside the SVG, but for some reason, I can't see the line output on my browser. There are no errors showing up either. Please he ...