Establish a function within an interface using the name obtained from a constant in Typescript

How can I define functions within an interface using constants as function names? I have a const array containing event names and I want to create an ServerToClientEvents interface for SocketIO.

I can define a function like this and it will work:

interface A {
    "funcName": () => void
}

But is it possible to use the constant values from FunNames as function names in this interface?

export const Events = {
    user_updated: "user:updated",
    empty: "empty"
}

interface ServerToClientEvents {
    Events.empty: () => void;
    Events.user_updated: (user: User) => void;
}   

Answer №1

If you find that Events is not dynamic, consider using const assertion.

export const Events = {
    user_updated: 'user:updated',
    empty: 'empty',
} as const;   //const assertion

interface User {
    id: string;
}
interface ServerToClientEvents {
    [Events.empty]: () => void;
    [Events.user_updated]: (user: User) => void;
}

Answer №2

To achieve this, utilize a mapped type along with a nested conditional type to test if the key being mapped matches a specific template literal type (to identify the need for the user parameter):

export const Events = {
    user_updated: "user:updated",
    empty: "empty",
};

type ServerToClientEvents = {
    [Key in keyof typeof Events]: Key extends `user_${string}` ? (user: User) => void : () => void;
};

const goodExample: ServerToClientEvents = {
    user_updated(user: User) {},
    empty() {},
};

const badExample: ServerToClientEvents = {
    //^^^^^^^^^^^−−−−− Property 'empty' is missing in type '{ user_updated(user: User): void; }' but required in type 'ServerToClientEvents'.ts(2741)
    user_updated(user: User) {},
};

Playground link

In my interpretation, the prefix user_ indicates that the function should accept a User object based on the provided code snippet, but feel free to adjust as needed.

Based on the defined Events constant, the mapped type outlines this structure:

{
    user_updated: (user: User) => void;
    empty: () => void;
}

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

For better readability, consider separating out the conditional type:

type ServerFunctionType<Key extends string> =
    Key extends `user_${string}`
        ? (user: User) => void
        : () => void;

type ServerToClientEvents = {
    [Key in keyof typeof Events]: ServerFunctionType<Key>;
};

Playground link

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 apply CSS modifications to sibling elements that are related?

I have several parent div elements with pairs of button and div child elements. My goal is to apply changes to the corresponding div when a button is clicked. For example, clicking Button 2 should only affect toast 2. However, I am facing an issue where o ...

Is there a way to determine if a route, or any of its nested routes, are currently active

Consider the following route examples: <Routes> <Route path="admin"> <Route path="users"> <Route index element={<UserList />} /> <Route path="create" element={<UserDetails ...

Creating a type definition for a TypeScript InfiniteScroll component in React

I am currently in the process of developing an InfiniteScroll component to be used like this: import { getData } from 'api'; import { InfiniteScroll } from 'components'; export const App = () => ( <InfiniteScroll fetcher={page ...

Show images exclusively on screens with a smaller resolution

Looking for assistance in modifying the code below to only display the image in mobile view, instead of constantly appearing. <style type="text/javascript> .icon-xyz {float: left; width: 22px;cursor: pointer;background: none;} @me ...

Tips for creating child divs with a width that spans the entire page

When viewing multiple rows of containers on my page, the elements shift inline on smaller screens. I am looking to have the orange bar positioned behind and slightly below the header, spanning the width of the page. To achieve this, I utilized relative pos ...

"Utilizing Bootstrap Tour for Easy Navigation: Automatically Scroll Back to the Top with

I have a Bootstrap tour set up with code that is meant to capture the user pressing the end tour button and scroll them back to the top of the screen. However, currently the code runs when a new popover loads instead of when the end tour button is clicke ...

Corporate firewall causing issues with AJAX call execution

Currently, I am utilizing jQuery's $.ajax() method to retrieve approximately 26KB of JSONP data. All major browsers including FF, Chrome, IE, and Safari are successfully returning the data from various locations such as work, home, and mobile phone w ...

Verify the functionality of a specific method invoked within another method through unit testing

I currently have a method in my Angular application that is triggered upon clicking. Inside this method, I pass a value to another private method. .ts file public onViewItem(item: Results): void { const ids = [item.data['id']]; this.anot ...

Having trouble getting the pull-right or float-right classes to work properly in Bootstrap 4?

Is there a way to update bootstrap-tabdrop.js to work with Bootstrap 4? Check out the Demo I tried changing pull-right to float-right but it didn't solve the issue :( Any assistance would be greatly appreciated. ...

What is the proper way to refactor this TypeScript class?

Can you assist me in converting this class into TypeScript and explaining why it's not functioning? class Students { public name: string; public surname: string; public age: number; } constructor(name:string,surname:string,age:number) { ...

Is it possible to resolve the error message "Uncaught TypeError: Cannot read property 'node' of undefined" when utilizing d3-tip with npm?

After installing d3": "^3.5.17" and "d3-tip": "^0.7.1" via npm (d3-tip documentation), the following code was added to my index.js file: var d3 = require('d3'); var d3tip = require('d3-tip')(d3); console.log('d3 version', d3. ...

I am attempting to display text in the input box on the console, but unfortunately, I am not seeing any changes in the console when typing

I have this code, but I am not getting any output when I run it: import { restaurantList } from "../config"; import { RestrauntCard } from "./Restraunt"; const Body = () => { const searchText = "KFC"; return ( <& ...

Is there a way to retrieve all properties within a Typescript Class that includes optional properties?

If we have a scenario where: class ExampleType { item1?: string, item2?: string } and all the properties are OPTIONAL. Is there a way to generate an array of property names like: ["item1", "item2"] I attempted to use console.log( ...

Transfer photos and videos to an external server using Javascript with Meteor framework

I currently have a meteor application hosted on Digital Ocean. I am considering setting up a dedicated server to store all images and videos separately from the site itself. Whenever a user uploads new media, it will be saved to this separate server. Does ...

How can MessagePorts be effectively utilized in electron Js?

What are some real-world applications of using MessagePorts in Electron JS? Why is it necessary instead of just using ipcRenderer.invoke? I haven't been able to identify any practical scenarios where MessagePorts are indispensable. It seems like it&ap ...

Infinite error loop during start-up in AngularJS application due to digest cycle overflow

Just starting out with Angular and working on a new project using node, jade, and angular. I'm having trouble implementing a catch-all server route. Every time the index page loads, it gets stuck in a loop and crashes the app. I've tried several ...

Showing the total quantity of products, reminiscent of a virtual shopping basket

I am trying to show a number similar to how a shopping cart displays items. The php code I was given currently shows a cookie value, which is mostly functional. However, if you encounter errors while adding items to the cart, it increases the cookie count ...

Using a TypeScript type in Angular 2 referencing

I have encountered an issue while referencing a custom type in Typescript that has left me puzzled. Despite my background in c#, I am facing difficulty using the correct syntax to reference the custom type. Here is my current setup: export type MyCustomeT ...

Discovering the method to read a file that is currently downloading in either JavaScript or Python

Imagine a scenario where I am actively downloading a file while simultaneously wanting to read its contents. However, the file is being continuously updated during the download process. For instance, if I start reading the file when the progress bar shows ...

You can only use the 'iframe' tag as a child of the 'noscript' tag. Were you trying to use 'amp-iframe' instead? - NextJs

We are currently experiencing an issue with AMP errors. The error message states: "The tag 'iframe' may only appear as a descendant of tag 'noscript'. Did you mean 'amp-iframe'?" It's important to note that custom JavaSc ...