Unraveling the mysteries of determining all potential generic types in TypeScript

I am dealing with a function that takes in a record of Handler<I, O> and outputs a function that provides the O value from one of the handlers:

type Handler<I, O> = { i: I, o: O, handler: (i: I) => O };

function handlerGroup<I, O>(handlers: Record<string, Handler<I, O>>): (key: string) => O {
  return (key: string) => {
    const { i, handler } = handlers[key];
    return handler(i);
  }
}

For instance:

const handleT1: Handler<number, number> = { i: 1, o: 1, handler: (i) => i }
const handleT2: Handler<number, string> = { i: 1, o: "1", handler: (i) => i.toString() }

handlerGroup({ T1: handleT1 }) //: (key: string) => number
handlerGroup({ T2: handleT2 }) //: (key: string) => string

The issue arises when I attempt to include more than one record:

// Type 'Handler<number, string>' is not assignable to type 'Handler<number, number>'.
//   Types of property 'o' are incompatible.
//     Type 'string' is not assignable to type 'number'.(2322)
handlerGroup({ T1: handleT1, T2: handleT2 }) // expected: (key: string) => number | string

This problem stems from how I defined the typing for handleGroup, which I'm currently unsure how to tackle.

So my question remains, how can I enable handleGroup to deduce all possible O values based on the provided record?

See playground

Answer №1

My approach involved reorganizing the handler into a generic form, allowing for the inference of its output:

type Handler<I, O> = { i: I, o: O, handler: (i: I) => O };

type A<T> = T extends Record<string, Handler<any, infer U>> ? U : never;

function handlerGroup<H extends Record<string, Handler<any, any>>>(handlers: H): (key: string) => A<typeof handlers> {
  return (key: string) => {
    const { i, handler } = handlers[key];
    return handler(i);
  }
}

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 'import.meta' meta-property can only be used with the '--module' set to 'es2020', 'esnext', or 'system'.ts(1343)

Whenever I attempt to utilize import.meta.url (as demonstrated in the Parcel docs), I am consistently met with the error message "The 'import.meta' meta-property is only allowed when the '--module' option is 'es2020', 'es ...

TS type defined by JS constants

I am currently working on a project that involves both JavaScript and TypeScript. I am trying to find a solution to reduce code duplication when using JavaScript string constants by converting them into TypeScript types. For example, let's say I have ...

Using ngIf to validate an empty string in Angular 5

I need assistance with validating an empty string retrieved from a server Although it is usually straightforward, it's just not working as expected <div class="ui-g-2 info-txt" *ngIf="appointment.Notes !==null || appointment.Notes !== ...

Unlimited Webpack watching cycle - tips on disregarding modifications in .js files, and more

There seems to be an issue with my webpack -w command when using ts-loader, as it is stuck in an endless loop. It appears that the problem arises because webpack -w detects changes in .js files, resulting in a continuous cycle: webpack -w => ts trans ...

Tips for transferring data from a service to a method within a component

I have a service that successfully shares data between 2 components. However, I now need to trigger a method in component A when an event occurs on the service (and pass a value to that component). Can someone guide me on how to achieve this? I have seen ...

Error TS2532 in TypeScript indicates that there is a possibility that the object is undefined

Yesterday, WebStorm 2020.1 was installed on my computer. All of a sudden, I started encountering numerous TS2532 errors. https://i.sstatic.net/QXg4M.png How is it even possible for this to be "undefined"? Doesn't selectedOwner && prevent th ...

NGRX Store: Unable to modify the immutable property '18' of the object '[object Array]'

While attempting to set up an ngrx store, I encountered 7 errors. Error Messages: TypeError: Cannot assign to read only property '18' of object '[object Array]' | TypeError: Cannot assign to read only property 'incompleteFirstPass ...

An error occurred with useState and localStorage: the parameter type 'string null' cannot be assigned to a parameter of type 'string'

I am currently using NextJS and attempting to persist a state using localStorage. Here is my code implementation: const [reportFavorite, setReportFavorite] = useState([ 'captura', 'software', 'upload', ] as any) ...

Is there cause for worry regarding the efficiency issues of utilizing Object.setPrototypeOf for subclassing Error?

My curiosity is piqued by the Object.setPrototypeOf(this, new.target.prototype) function and the cautionary note from MDN: Warning: Modifying an object's [[Prototype]] is currently a slow operation in all browsers due to how modern JavaScript engines ...

Can we modify the auto-import format from `~/directory/file` to `@/directory/file`?

I have a small issue that's been bugging me. I'm working on a project using Nuxt3 and Vscode. When something is auto-imported, Vscode uses the ~/directory/file prefix instead of the preferred @/directory/file. Is there an easy way to configure Vs ...

A guide on instantly updating displayed flat/section list elements in React Native

I am in the process of creating a screen called ContactListScreen. The direct child of ContactListScreen is ContactItems, which is a sectionList responsible for rendering each individual ContactItem. However, I have encountered a problem where my ContactIt ...

Utilizing GroupBy in RxJs for an Observable of Objects数组

I am working with entries of type Observable<Event[]>, and they are structured as follows: [{ "_id": 1, "_title": "Test Event 1", "_startDate": "2019-05-29T07:20:00.000Z", "_endDate": "2019-05-29T08:00:00.000Z", "_isAllDay": false }, ...

Learn how to resolve the issue of "Property 'item' does not exist on type 'never'." in Angular using TypeScript with the following code snippet

addToCart (event: any) { if ("cart" in localStorage) { this.cartProducts = JSON.parse(localStorage.getItem("cart")!) console.log(event); let exist = this.cartProducts.find(item => item.item.id == event.item.id); ...

When attempting an Axios request, the backend method cannot be accessed

I am facing an issue when using Axios request to access a method in the backend. I am constrained by pre-existing code in both frontend and backend that limits how much I can modify or add. Frontend: const response = await axiosConfig.put<IReserved&g ...

What advantages does using a callback offer compared to await?

For a project focused on user-related tasks, I crafted the following code snippet within my service file. let result: User | null = await userModel.registerUser(); return result; After receiving feedback from my team advising to "Use callback rather than ...

Error TS2315: Invalid Type Assignment for Angular 6 ModuleWithProviders

Hey there, I'm encountering an issue that's got me scratching my head. I've shared some of my code in the hopes that it might shed some light on the problem. The problem cropped up as soon as I started working on a Reactive Form. Let me s ...

Unable to utilize material tabs in this situation

Discovering the material tabs feature at https://material.angular.io/components/tabs/api#MatTab got me excited to implement it in my project. After adding the suggested import, I encountered an issue where I couldn't find the module "@angular/materia ...

I am searching for answers to solve issues related to a JSON file

I am currently working on a tool that searches for matches in an input field by comparing the keywords entered by the user with a JSON. During my testing phase, I focused on using a single API that provides information about different countries and fortun ...

The MemoizedSelector<ICommonAppState, IMenuItemsObject[]> argument does not match the expected 'string' parameter type

I have implemented the use of createSelector from @ngrx/store in order to select an array of objects from my store. Despite successfully compiling my application, I encountered the following error: Argument of type 'MemoizedSelector<ICommonAppSta ...

What is the best way to hold out for a specific number of promises to be fulfilled and halt the resolution of any others

While working in TypeScript, I need to create around 100 instances of Promise. However, I am only interested in waiting for the resolution of 5 of them. Any promises beyond that can either be canceled (if feasible) or rejected since they are no longer requ ...