Assigning the lookup type from a generic type to "any" is not allowed

Trying to explain this may be a bit challenging. The example provided is intricate, but efforts have been made to simplify it while retaining the error.

type Handler = (...args: any[]) => void;

const handlers: { [eventName: string]: Handler } = {};

type Events = {
  // Map event signature (arg types) to event name
  [eventName: string]: any[];
};

function createOnEvent<UserEvents extends Events>() {
  type ValidEventName = Extract<keyof UserEvents, string>;

  return <EventName extends ValidEventName>(
    eventName: EventName,
    eventHandler: (...args: UserEvents[EventName]) => void,
  ) => {
    handlers[eventName] = eventHandler; // [0] ERROR HERE
  };
}

[0] Type 'any[]' is not assignable to type 'UserEvents[EventName]'

There are two points of confusion:

  • UserEvents[EventName] should match any[]
  • The attempt is to assign UserEvents[EventName] to any[], not vice versa...

Here is how this API can be utilized:

type FooEvents = {
  eventOne: [number];
  eventTwo: [string, boolean];
};

const onEvent = createOnEvent<FooEvents>();
onEvent('eventOne', (arg1: number) => null); // OK
onEvent('eventTwo', (arg1: string, arg2: boolean) => null); // OK
onEvent('eventOne', (arg1: string) => null); // error

Everything seems to work fine except for storing the handler in handlers, which should accept functions with any argument list.

This situation may seem perplexing, so feel free to ask for clarification if needed. It would be great to resolve this issue. Thank you!

Answer №1

Issue Explanation

The error you are encountering is due to the behavior of function types being contravariant in their argument type when the --strictFunctionTypes flag is activated.

In simpler terms, this means that a function can accept arguments that are either as specific or broader than what is expected by its parameter type.

Your scenario involves a dictionary of generic handlers called handlers. These handlers are designed to work with arguments of type any[]. Their definition could have been written as follows:

const handlers: {
  [eventName: string]: (...args: any[]) => void
} = {};

However, the issue arises because your eventHandler is not just a generic handler. It requires arguments specifically defined by UserEvents, which contradicts the principle of contravariance — arguments passed to a function should not be more precise than those specified by its signature. In essence, typeof eventHandler is not compatible with Handler.

Possible Solutions

  • You can temporarily widen the type of eventHandler by using a type assertion locally:

    handlers[eventName] = eventHandler as Handler;
    
  • Alternatively, you may modify the compiler to acknowledge specific definitions of a handler:

    type Handler<T extends any[] = any> = (...args: T) => void;
    

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

Navigating the dot notation to uncover the data type of a field within an object

When working with an object type, we can access the type of one of its fields using bracket-string notation. However, why isn't it possible to use dot notation like in JavaScript? Could there be a conflict or some other reason for this limitation? I h ...

Is it possible to display Angular Material Slider after the label?

Searching through the Angular Material docks, I came across the Sliders feature. By default, the slider is displayed first, followed by its label like this: https://i.sstatic.net/C5LDj.png However, my goal is to have the text 'Auto Approve?' sh ...

Error message: The database query function is encountering an issue where the property 'relation.referencedTable' is undefined and cannot be accessed

Currently, I am working with two schemas named products.ts and category.ts. The relationship between these files is defined as one-to-many. In the products.ts file: import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; import ...

Steps for transferring an uploaded .CSV file to a Web service

I'm exploring the process of sending a file uploaded from the UI (angular) to a .NET web service in order for it to parse a CSV file and create a list of objects. My current understanding of the logic flow is: File upload ---> Web Service (parse ...

`Planning the layout of an Angular application with distinct sections`

I've been working on breaking down my Angular app into separate sections and I have a few queries about how to proceed: auth login (only public page in the entire system, after login users are directed to either the admin or user portal based on ...

Leveraging npm for the development of my TypeScript/Node.js project

I'm facing challenges working on a project written in TypeScript and running on Node. I am finding it difficult to write the npm script to get it up and running properly for development purposes. What I am attempting to achieve is: clear the /dist f ...

"I'm looking for a way to store and fetch TypeScript objects with PouchDB. Any suggestions on

As someone who is new to typescript and web development, I am eager to incorporate PouchDB into my typescript project to store my objects. Despite the lack of documentation, I am struggling to find the correct approach. I have created typescript objects t ...

Exploring Angular2's interaction with HTML5 local storage

Currently, I am following a tutorial on authentication in Angular2 which can be found at the following link: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492 I have encountered an issue with the code snippet below: import localSt ...

Angular: Unable to locate route declaration in the specified path /src/app/app-routing.module.ts

Whenever I attempt to set up automatic routing for components that have been created using the command below ng generate module orders --route orders --module app.module I encounter the following error message The requested URL /src/app/app-routing.mod ...

tRPC asynchronous mutation does not have a return value

Attempting to utilize tRPC for the first time here. I have created a mutation called "add" that takes a URL as input and returns a hardcoded slug. Router export const entryRouter = router({ add: publicProcedure .input(input) .output(output) ...

Creating a JSON file using an object to send requests in Angular

In my Angular 7 project, I am trying to send a multipart request to the server that includes a file (document_example.pdf) and a json file containing a data object (data_object_example.json). The content of data_object_example.json is as follows: { " ...

Having trouble updating an NPM dependency within package.json that is already installed as a dependency

I encountered an error message while trying to import mongoose with TypeScript node_modules/mongoose/node_modules/mongodb/mongodb.d.ts:3309:5 - error TS2416: Property 'end' in type 'GridFSBucketWriteStream' is not assignable to the same ...

What is the method for referencing a subtype within an established type?

When working with React-native, I came across a component called FlatList which includes a property known as ListHeaderComponent. My question is how to specify the type of this property without having to manually copy and paste the original type. Currentl ...

Restrict function signatures in Typescript to only accept class or object methods

In my quest to create a function signature in Typescript, I am looking to develop a calling function that takes an object, its method name, and arguments to be applied. Here is an example of it in action: const obj = { do(...args) { console.log(arg ...

Encountering a Typescript issue when trying to access props.classes in conjunction with material-ui, react-router-dom

I could really use some help with integrating material-ui's theming with react-router-dom in a Typescript environment. I'm running into an issue where when trying to access classes.root in the render() method, I keep getting a TypeError saying &a ...

What could be causing the module version discrepancy with the package.json file I created?

Recently, I created a project using create-next-app and decided to downgrade my Next.js version to 12. After that, I proceeded to install some necessary modules using Yarn and specified the versions for TypeScript, React, and others. During this setup, I b ...

JavaScript and JSX file formats are used for a variety of types

I am currently delving into the react-grid-layout library, and I find myself perplexed by the presence of types in .js/.jsx files. Here's an example excerpt from a .jsx file: type Props = { children: ReactElement<any>, cols: number, conta ...

TS1343: Usage of the 'import.meta' meta-property is restricted to when the '--module' flag is set to 'es2020', 'es2022', 'esnext', 'system', 'node16', or 'nodenext' mode

Whenever I attempt to compile my project into esm and cjs, I encounter this error consistently. This is the content of my package.json: { "name": "qa-data-tool", "version": "1.0.0", "descript ...

The integration of Tailwind merge is experiencing issues when used with CSS modules

My Next.js project utilizes Tailwind for styling elements, and I rely on Tailwind's merge feature to address class precedence issues within my components. It appears that the merge feature does not function correctly when working with CSS modules (spe ...

Are fp-ts and Jest the perfect pairing for testing Option and Either types with ease?

When working with fp-ts, and conducting unit tests using Jest, I often come across scenarios where I need to test nullable results, typically represented by Option or Either (usually in array find operations). What is the most efficient way to ensure that ...