What's the most efficient way to define the type of an object in TypeScript when one of its properties shares the same name as the type itself?

I'm currently working on processing an event payload where the event field is a string, and the content of data depends on the value of the event field. While I have come up with a representation that functions correctly, I can't help but feel that there might be a better or more conventional approach:

type EventMap = {
  created: { created: string },
  updated: { updated: string }
}

type Payload<T extends keyof EventMap> = {
  event_id: string;
  event: T;
  data: EventMap[T];
};

type Payloads = Payload<'created'> | Payload<'updated'>

It seems redundant to keep mentioning created and updated. However, using Payload<keyof EventMap> doesn't quite fit either as it allows for any combination.

Answer №1

You can achieve something similar by doing the following:

type Payloads = { [K in keyof EventMap]: Payload<K> }[keyof EventMap]

Playground

Alternatively, you can directly create the Payloads type from the EventMap:

type Payloads = {
    [K in keyof EventMap]: {
        event_id: string;
        event: K;
        data: EventMap[K];
    }
}[keyof EventMap]

Playground


// works
const x: Payloads = {
    event_id: 'x',
    event: 'created',
    data: {
        created: 's'
    }
}

// works
const y: Payloads = {
    event_id: 'x',
    event: 'updated',
    data: {
        updated: 's'
    }
}

// error due to mixed updated and created
const z: Payloads = {
    event_id: 'x',
    event: 'updated',
    data: {
        created: 's'
    }
}

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

Using an external HTML file to import a template into Vue.js single file components

I've been tackling a Vuejs project that involves using vue-property-decorator in single file components. I'm trying to figure out how to import the template from an external HTML (or different) file, but so far I haven't found a solution. I& ...

TypeScript's type 'T' has the potential to be instantiated with any type, even if it is not directly related to 'number'

Let's say we have a function that takes a value (for example, number) and a callback function that maps that value to another value. The function simply applies the provided callback: function mapNumber<T>(value: number, mapfn: (value: number) = ...

What is the correct way to declare a class as global in TypeScript?

To prevent duplication of the class interface in the global scope, I aim to find a solution that avoids redundancy. The following code snippet is not functioning as intended: lib.ts export {} declare global { var A: TA } type TA = typeof A class A { ...

Tips for utilizing PNG images in Next.js beyond the conventional PUBLIC folder

I have been trying to use images from a directory other than the Public folder by implementing the Next-Images library. Despite following the setup instructions in the documentation and watching various tutorials online, I am unable to load anything other ...

Verifying TypeScript Class Instances with Node Module Type Checking

My current task involves converting our Vanilla JS node modules to TypeScript. I have rewritten them as classes, added new functionality, created a legacy wrapper, and set up the corresponding Webpack configuration. However, I am facing an issue with singl ...

Looking for a way to include an input box within a react-select option dropdown menu

Currently, I am facing a situation where I need to include an input box within my dropdown option menu. The challenge is that I cannot utilize the custom tag creator feature of react select to create a new option with the dropdown. Upon going through the ...

Encountering a TypeScript error in Vue 3 when trying to assign a type of '($event: any) => void' to an event listener

Snippet of component code: <h2 @click="handleEvent(post.id)">{{ post.title }}</h2> function handleEvent(id: number) { router.push("/post/" + id); } Error message in TypeScript: Type '($event: any) => void' i ...

Custom Angular directive for collapsing sub menus with CSS

I found a helpful article on creating collapsible menus and submenus using only Bootstrap and custom code for Angular 2, 4, 5, 6. I've been able to implement the logic successfully, but I'm facing an issue with multiple menus where clicking on an ...

Each time the Angular Service is called, it undergoes a reset process

For my Angular web project, I have implemented an AuthenticationGuard and an AuthenticationService to manage security. These components are from a separate branch of the project that is functioning perfectly. This is how the process should occur: Go to ...

Service error: The function of "method" is not valid

In one of my Angular 2 applications, I have a class that contains numerous methods for managing authentication. One particular method is responsible for handling errors thrown by the angular/http module. For example, if a response returns a status code o ...

Enhancing Luxon DateTime with extension type support

Referencing the issue at https://github.com/moment/luxon/issues/260, I am looking to extend the DateTime object as shown below: import { DateTime } from 'luxon'; function fromUnix(tsp?: number): DateTime { return DateTime.fromMillis(tsp * 1000 ...

How can Vue Router be integrated with Vue.JS SSR?

Despite reading up on SSR documentation, I am struggling to make it work (I feel lost). I created the project with Vue CLI using 'vue new frontend'. I opted for typescript and configured all settings in package.json. Additionally, I am utilizing ...

Refine a union type by considering the properties already defined in an object

interface CustomHTMLElement { htmlPropA: string, htmlPropB: string, } interface CustomHTMLInput { inputPropA: string, inputPropB: string, } type CustomElement = | CustomHTMLElement | CustomHTMLInput const element: CustomElement = { inputPr ...

Hand over the component method as an argument to a class

One of my components, called First, is responsible for creating a new instance of a Worker class. During the creation process of this class, I intend to pass the Read method as a callback method. Once this class completes its task, it will then invoke thi ...

Limiting the Rate of Requests to a TCP Server using net.Server

I've been utilizing net.Server as my TCP server. Is there a way to impose a message rate limit? I managed to find solutions for enforcing rate limits in Express (express-rate-limit) and Websocket (websocket-rate-limit), but nothing specifically for ...

Module `coc-tsserver` not found (error ts2307)

https://i.sstatic.net/k1MVW.png Working on a project using NeoVim with CoC for TypeScript development in a yarn-3 pnp-enabled environment. Suddenly, the editor stopped recognizing imports and started showing errors for non-existent modules (refer to the s ...

When using RXJS, the method BehaviorSubject.next() does not automatically notify subscribers

In my project, I have a service set up like this: @Injectable({ providedIn: 'root' }) export class MyService { private mySubject = new BehaviorSubject({}); public currentData = this.mySubject.asObservable(); updateData(data: any) { ...

Encountering an error while receiving a response for the Update API request

Recently, I ventured into the world of swagger and decided to test it out with a small demo project in node-js. I successfully created 5 APIs, but encountered an issue specifically with the PUT API. Surprisingly, when testing it on Postman, everything work ...

Managing a digital timepiece within a multiplayer gaming environment

I'm currently developing a fast-paced game where players control a block resembling a clock. To accurately calculate the time taken by each player to make moves, I store the start time of the game and record the timestamp of every move in the databas ...

The typescript compiler encounters an error when processing code that includes a generator function

Recently, I started learning about TypeScript and came across the concept of generators. In order to experiment with them, I decided to test out the following code snippet: function* infiniteSequence() { var i = 0; while(true) { yield i++ ...