Tips for creating a universal function for two interlinked types

My goal is to establish an abstract relationship between different sub-types of Message and Response, allowing for a generic function that takes a Message as input and returns a corresponding Response. Specifically, when the function is called with type MessageTypeA, I want the response type to always be ResponseTypeA, and I need TypeScript to enforce this connection in some way. Here's a depiction of the issue using TypeScript:

type MessageTypeA = { a: string };
type MessageTypeB = { b: number };
type MessageTypeC = [number, number];

type Message = MessageTypeA | MessageTypeB | MessageTypeC;

type ResponseTypeA = { a: boolean; aa: number };
type ResponseTypeB = "hello" | "bye";
type ResponseTypeC = number;

type Reponse = ResponseTypeA | ResponseTypeB | ResponseTypeC;

type Pair<M extends Message, R extends Reponse> = {
  message: M;
  response: R;
};

// Ideally should use a Map/Record instead
type ValidPairsMap =
  | Pair<MessageTypeA, ResponseTypeA>
  | Pair<MessageTypeB, ResponseTypeB>
  | Pair<MessageTypeC, ResponseTypeC>;

// A rough implementation attempt:
function sendMessageReturnResponse<T extends ValidPair>(
  message: typeof T.message
): typeof T.response {
  throw "uncertain how to accomplish this";
}

function main() {
  let mesA: MessageTypeA = { a: "msg" };
  let resA: ResponseTypeA = sendMessageReturnResponse(mesA);
  // error: return value of sendMessageReturnResponse cannot be inferred to be ResponseTypeA
}

In light of this challenge, what steps can I take to achieve the intended outcome?

Answer №1

If you are in need of a code snippet similar to this:

type MessageTypeA = { a: string };
type MessageTypeB = { b: number };
type MessageTypeC = [number, number];

type Message = MessageTypeA | MessageTypeB | MessageTypeC;

type ResponseTypeA = { a: boolean; aa: number };
type ResponseTypeB = "hello" | "bye";
type ResponseTypeC = number;

type Reponse = ResponseTypeA | ResponseTypeB | ResponseTypeC;

type Pair<M extends Message, R extends Reponse> = {
    message: M;
    response: R;
};

type ValidPairsMap =
    | Pair<MessageTypeA, ResponseTypeA>
    | Pair<MessageTypeB, ResponseTypeB>
    | Pair<MessageTypeC, ResponseTypeC>;

// The following function has incorrect syntax:
function sendMessageReturnResponse<Msg extends Message>(
    message: Msg
): Extract<ValidPairsMap, Pair<Msg, any>>['response'] {
    return null as any
}

function main() {
    let mesA: MessageTypeA = { a: "msg" };
    let resA: ResponseTypeA = sendMessageReturnResponse(mesA); // ok

}

Playground

In sendMessageReturnResponse, only inferring Message is necessary, allowing you to filter the union type using Extract

This line

Extract<ValidPairsMap, Pair<Msg, any>>
signifies retrieving the Pair where the message is Msg from the union of ValidPairsMap

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 'HTMLDivElement' type does not include the property 'prepend' in Typescript

When working with a typescript method, the following code snippet is used: some_existing_div.prepend(some_new_div) This may result in an error message: [ts] Property 'prepend' does not exist on type 'HTMLDivElement'. However, despi ...

Experience the dynamic live preview feature of Sanity integrated with NextJS 13

I am facing an issue with checking if preview mode is activated on my website. While following a YouTube tutorial, I realized that the instructions may be outdated with the latest NextJS update. This was the code snippet I was originally working with to ...

Understanding Angular's Scoping Challenges

I have a function that retrieves an array and assigns it to this.usStates. main(){ this.addressService.getState().subscribe( (data:any)=>{ this.usStates = data; if(this.usStates.length===0) { this.notificationServic ...

Guide to utilizing services in Angular 2

As I've developed a service with numerous variables and functions, my goal is to inject this service into multiple components. Each component should have the ability to update certain variables within the service so that all variables are updated once ...

Receiving an error stating "module not found" when attempting to retrieve the NextAuth session using EmailProvider in getServerSideProps

Trying to access the NextAuth session from a server-side call within getServerSideProps, using an EmailProvider with NextAuth. Referring to an example in NextAuth's documentation, I'm attempting to retrieve the session from getServerSideProps. T ...

Infinite Loop Issue in Angular2 RC5 when using the templateUrl

Encountering an issue with Angular2 RC5 that seems to be causing an infinite loop problem. The app.component, which is bootstrapped by the app.module, appears quite simple: @Component({ selector: 'my-app', template: `TEST` }) export cl ...

Collaborate on sharing CSS and TypeScript code between multiple projects to

I am looking for a solution to efficiently share CSS and TS code across multiple Angular projects. Simply copy-pasting the code is not an ideal option. Is there a better way to achieve this? ...

I've tried using a ControlValueAccessor, but for some reason the value isn't getting passed to the form

Currently, I am experimenting with reactive forms in Angular, and I'm encountering difficulties with updating the form from custom components. As an example, take a look at the date-input component created using flatpickr in the linked Plunker demo. ...

Create a prop type that can be either a single number or an array of numbers, depending on the value of another

Seeking a solution, I am exploring an example using arrays with the 'multi' property. When 'multi' is true, the items should be of type number[]. Otherwise, they should be of type number. interface EnhancedSelectProps { items: multi ? ...

In TypeScript, the argument 'xxx' cannot be passed to a parameter expecting a 'string' type

When I try to create a new Error object with the message {code: 404, msg: 'user is not existed'} in TypeScript, I receive the following error message: [ts] Argument of type '{ code: number; msg: string; }' is not assignable to paramete ...

Conditional types can be used as type guards

I have this simplified code snippet: export type CustomType<T> = T extends Array<unknown> ? {data: T} : T; function checkAndCast<T extends Array<unknown>>(value: CustomType<T>): value is {data: T} { return "data" ...

What could be causing my code to not run after subscribing to the observables?

In my code, I have two methods that return two lists: one for accepted users and the other for favorite users. The first part of my code works well and returns both lists, but in the second part, I need to filter out the accepted users who are also on the ...

Leverage the JSON Web Token module within a Chrome extension

Currently in the process of developing a chrome extension but encountering an issue with loading the json web token node module in my Node.js setup. background-script.ts import jwt from 'jsonwebtoken'; // import * as jwt from '../node_mod ...

An error message occurs in TypeScript when trying to access a property that does not exist in an array

I'm having trouble figuring out this issue... I am receiving data from an API and storing it as an array. I'm attempting to access the data in this format... this.data.results[i].datas[j].dataType However, I keep getting the error "property res ...

Exploring Child Types in Typescript and JSX minus the React framework

It seems like there's a missing piece of the puzzle that I can't quite figure out. Despite going through the documentation on JSX in non-React settings, I'm still unable to spot my mistake. Let's examine the following code: /** @jsx pra ...

Exploring the functionality of className using materialUI

Attempting to test whether my component has a specific class is proving challenging. This difficulty stems from the fact that the class is generated using MaterialUI. For instance, I am looking for a class named spinningIconCenter, but in reality, it appea ...

Tips for integrating TypeScript files into Next.js HTML files

Encountering an issue while trying to load a typescript file from HTML, resulting in this error Here is the code snippet for the page: export default function Home() { return ( <> <Script src="/static/main.tsx"></Scri ...

AWS Amplify is failing to maintain the user session post a successful login

Currently, I am developing an aws-serverless application using React. My main issue lies in the authentication process with aws-amplify. The authentication works smoothly, but the session is not being preserved. During the signing-in stage: await Auth.s ...

What steps are required to utilize NgbSortableHeader for sorting a bootstrap table through programming?

I have a bootstrap HTML table (operated by ng-bootstrap for Angular and utilized NgbdSortableHeader to arrange table columns by clicking on the column). When I click on an element, it sorts the column in ascending, descending, or ''(none) order. ...

Encountering difficulties importing in Typescript and ts-node node scripts, regardless of configuration or package type

I am facing a challenge with my React Typescript project where multiple files share a similar structure but have differences at certain points. To avoid manually copying and pasting files and making changes, I decided to create a Node script that automates ...