Create a constant object interface definition

Is there a way to create an interface for an object defined with the as const syntax?

The Events type does not work as intended and causes issues with enforcement.

const events = { // how can I define an interface for the events object?
    test: payload => console.log(payload),
    another: payload => console.log(payload)
} as const;

type Events = { [key: string]: (payload: Payload) => void }; // this approach does not work for events object
type Payload = { [key: string]: any };
type EventName = keyof typeof events;

const emit = (event: EventName, payload: Payload) => {
    events[event]?.(payload); 
} // (parameter) event: "test" | "another"

emit('foo', { test: 1 }); // Argument of type '"foo"' is not assignable to parameter of type '"test" | "another"'.

View TS Playground

Answer №1

To ensure the correct parameters type for the function emit, you can abstract an interface from the shape of the events object:

// Defining the events object.
// Specify the payload type if it's not `any`.
const events = {
    test: (payload: any) => console.log(payload),
    another: (payload: {test:number}) => console.log(payload),
} as const;

// Extract event names from the object keys.
type EventName = keyof typeof events;

// Determine the payload type for each event.
// `Parameters` extracts the function parameters and returns them as an array.
// Ex: Parameters<(a: string, b: number) => void> returns [string, number].
type Payload = { [key in EventName]: Parameters<typeof events[key]>[0] };

// Define the `emit` function with types.
const emit = <T extends EventName>(event: T, payload: Payload[T]) => {
    events[event]?.(payload); 
}

emit('test', {anything: 'can be passed'}); // `test` can take any payload.
emit('another', {test: 2}); // `another` requires an object with a `test` property.
emit('another', {}); // Not specifying the property will result in an error.

playground

If you need to add support for another event, simply include it in the events object.

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

Leveraging Promise in conjunction with async/await

As I venture into the world of async/await in TypeScript, I find myself pondering a few questions. Specifically, I have been working on a function to extract an ArrayBuffer from a Blob. async function readAsArrayBuffer(blob: Blob): Promise<ArrayBuffer& ...

Currency symbol display option "narrowSymbol" is not compatible with Next.Js 9.4.4 when using Intl.NumberFormat

I am currently utilizing Next.JS version 9.4.4 When attempting to implement the following code: new Intl.NumberFormat('en-GB', { style: 'currency', currency: currency, useGrouping: true, currencyDisplay: 'narrowSymbol'}); I ...

Angular Authentication Functionality

I need to create a loggedIn method in the AuthService. This method should return a boolean indicating the user's status. It will be used for the CanActivate method. Here is a snippet of code from the AuthService: login(email: string, password: string) ...

Establishing a Next.js API endpoint at the root level

I have a webpage located at URL root, which has been developed using React. Now, I am looking to create an API endpoint on the root as well. `http://localhost:3000/` > directs to the React page `http://localhost:3000/foo` > leads to the Next API end ...

Dragging element position updated

After implementing a ngFor loop in my component to render multiple CdkDrag elements from an array, I encountered the issue of their positions updating when deleting one element and splicing the array. Is there a way to prevent this unwanted position update ...

In Angular 6, triggering a reset on a reactive form will activate all necessary validators

As a beginner in angular 6, I am currently facing an issue with resetting a form after submitting data. Although everything seems to be functioning properly, when I reset the form after successfully submitting data to the database, it triggers all the req ...

Trouble integrating PDF from REST API with Angular 2 application

What specific modifications are necessary in order for an Angular 2 / 4 application to successfully load a PDF file from a RESTful http call into the web browser? It's important to note that the app being referred to extends http to include a JWT in ...

Using TypeScript in the current class, transform a class member into a string

When converting a class member name to a string, I rely on the following function. However, in the example provided, we consistently need to specify the name of the Current Component. Is there a way to adjust the export function so that it always refers ...

What could be the reason for the component not receiving data from the service?

After attempting to send data from one component to another using a service, I followed the guidance provided in this answer. Unfortunately, the data is not being received by the receiver component. I also explored the solution suggested in this question. ...

Steer clear of chaining multiple subscriptions in RXJS to improve code

I have some code that I am trying to optimize: someService.subscribeToChanges().subscribe(value => { const newValue = someArray.find(val => val.id === value.id) if (newValue) { if (value.status === 'someStatus') { ...

Is there a way to monitor user engagement within my app without depending on external analytics platforms?

I'm looking to enhance the user-friendliness of my applications deployed on the Play Store by tracking users' interactions. Specifically, I want to keep track of: Screen Time: Monitoring how much time users spend on each screen. Clicks: Tracking ...

There is an issue with the Angular Delete request functionality, however, Postman appears to be

HttpService delete<T>(url: string): Observable<T> { return this.httpClient.delete<T>(`${url}`); } SettingsService deleteTeamMember(companyId: number, userId: number): Observable<void> { return this.httpService.delete< ...

The bar chart functions perfectly on localhost but encounters issues after being hosted on Gitpage

Localhost Gitpage The bar chart was displaying correctly on localhost, but once it was hosted on Gitpage, it began to show issues. Any suggestions on how to resolve this? Repository Link: https://github.com/mzs21/bar-chart Live Preview: ...

Jest is having trouble recognizing a custom global function during testing, even though it functions properly outside of testing

In my Express app, I have a custom function called foo that is globally scoped. However, when running Jest test scripts, the function is being recognized as undefined, causing any tests that rely on it to fail. This is declared in index.d.ts: declare glob ...

Function with a TypeScript Union Type

I'm attempting to define a property that can be either a lambda function or a string in TypeScript. class TestClass { name: string | () => string; } You can find a sample of non-working code on the TS playground here. However, when compiling ...

Arranging Pipe Methods in RxJS/Observable for Optimal Functionality

In the class Some, there is a method called run that returns an Observable and contains a pipe within itself. Another pipe is used when executing the run method. import { of } from 'rxjs'; import { map, tap, delay } from 'rxjs/operators&ap ...

Is it possible to update input form fields in an Angular application?

I am currently designing a straightforward web page featuring a modal for creating a new object named Partner and sending it to the server. The page also includes multiple input fields to showcase the newly created data. In this project, I am utilizing Ang ...

Issue in TypeScript: The module "*.svg" does not have a component that is exported named "ReactComponent"

I'm attempting to bring in an .svg file as a React component using TypeScript. As per the React documentation, the process should look like this: import { ReactComponent as Icon } from './Icon.svg'; Referring to the TypeScript documentati ...

Typescript: The type 'X' does not correspond with the signature '(prevState: undefined): undefined' in any way

My React Native app, which is written in TypeScript, has been giving me a hard time with an error lately. The issue revolves around a Searchable List feature. This list starts off with an Array of values and gets updated when users type into a search bar. ...

Typescript not being transpiled by Webpack

As I set out to create a basic website, I opted to utilize webpack for packaging. TypeScript and SASS were my choice of tools due to their familiarity from daily use. Following the documentation at https://webpack.js.org, I encountered issues with loaders ...