Different types of TypeScript interface keys being derived from an enum

How can I efficiently implement a list of properties to be used as keys in interfaces with different types? I want to restrict the use of properties that do not exist in an enum.

export enum SomeProperties {
  prop1,
  prop2,
  prop3
};

export interface PropsInterface {
  [SomeProperties.prop1]: number;
  [SomeProperties.prop2]: boolean;
  [SomeProperties.prop3]: string;
}


// Example of how to use it. 
// I have an object of properties. Each property can be updated individually.

let props: PropsInterface = {
   [SomeProperties.prop1]: null,
   [SomeProperties.prop2]: null,
   [SomeProperties.prop3]: null
};

const fieldToUpdate: {
  field: SomeProperties;
   value: number;
} = {
   field: SomeProperties.prop1,
   value: 123
};

props[fieldToUpdate.field] = fieldToUpdate.value;

Answer №1

To start, ensure that all properties in the PropsInterface are nullable.

export enum SomeProperties {
  prop1,
  prop2,
  prop3
};

interface PropsBase {
  [SomeProperties.prop1]: number;
  [SomeProperties.prop2]: boolean;
  [SomeProperties.prop3]: string;
}

type NullableRecord<T> = {
  [Prop in keyof T]: T[Prop] | null
}

type PropsInterface = NullableRecord<PropsBase>

Once that is done, you can assign null as a property type.

let props: PropsInterface = {
  [SomeProperties.prop1]: null,
  [SomeProperties.prop2]: null,
  [SomeProperties.prop3]: null
}

However, there might be an issue with the following code:

const fieldToUpdate = {
  field: SomeProperties.prop1,
  value: 123
}

props[fieldToUpdate.field] = fieldToUpdate.value;

The problem arises because fieldToUpdate.field is inferred as an enum, expecting all keys, while you only need SomeProperties.prop1.

To resolve this, simply use the as const assertion.

const fieldToUpdate = {
  field: SomeProperties.prop1,
  value: 123
} as const

props[fieldToUpdate.field] = fieldToUpdate.value;

Here is the complete code snippet:

export enum SomeProperties {
  prop1,
  prop2,
  prop3
};

interface PropsBase {
  [SomeProperties.prop1]: number;
  [SomeProperties.prop2]: boolean;
  [SomeProperties.prop3]: string;
}

type NullableRecord<T> = {
  [Prop in keyof T]: T[Prop] | null
}

type PropsInterface = NullableRecord<PropsBase>


// Example of usage. 
// An object with properties that can be updated individually.

let props: PropsInterface = {
  [SomeProperties.prop1]: null,
  [SomeProperties.prop2]: null,
  [SomeProperties.prop3]: null
};

const fieldToUpdate = {
  field: SomeProperties.prop1,
  value: 123
} as const

props[fieldToUpdate.field] = fieldToUpdate.value;

Playground

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

Utilize the provider within the decorator function

Essentially, the challenge I am facing is passing an authService to the "verifyClient" function within the @WebSocketGateway decorator. Here is how it should look: @WebSocketGateway({ transports: ['websocket'], verifyClient: (info: { req: Inc ...

It's possible that the "device.interfaces" variable has not been defined

I am currently working on creating a USB driver in TypeScript using the libusb library to adjust my keyboard lighting. However, I encountered an issue where I received a 'possibly undefined' error when trying to retrieve the interface number. The ...

What is the method for incorporating a customized button into the header of a Dynamic Dialog using PrimeNG?

I'm currently working on a project using Angular v17 and PrimeNG. I need to add buttons to the header of a dynamic dialog, but I've been struggling to find a solution. Here's the code snippet from my dialog component: show(j): void { ...

Exploring the Power of Observables in Angular 2: Focusing on Targeting an Array Nested Within

I encountered a situation where I was successfully looping through objects in an array within my Angular 2 application using observables. In the client service file, my code looked like this: getByCategory(category: string) { const q = encodeURICompon ...

Is there a way for me to simultaneously run a typescript watch and start the server?

While working on my project in nodejs, I encountered an issue when trying to code and test APIs. It required running two separate consoles - one for executing typescript watch and another for running the server. Feeling frustrated by this process, I came ...

Setting up Webpack for Node applications

My current challenge involves configuring Webpack for a node app that already exists. I am encountering various issues and struggling to find solutions or even know where to begin. Situation The project's folder structure is as follows: +---app +-- ...

Utilizing a conditional ngIf statement in HTML or incorporating a variable within typescript for logical operations

When working with our application, we often need to display or hide a button based on specific logic. Where do you think it is best to define this logic and why? In HTML: *ngIf='logic goes here' //Or *ngIf='someBoolean' and in Type ...

Using Jest: A guide to utilizing a mocked class instance

When working on my frontend React application, I decided to use the auth0-js library for authentication purposes. This library provides the WebAuth class which I utilize in my code by creating an instance like so: import { WebAuth } from 'auth0-js&ap ...

Using Vuetify to filter items in a v-data-table upon clicking a button

My table structure is similar to this, https://i.sstatic.net/56TUi.png I am looking to implement a functionality where clicking on the Filter Button will filter out all items that are both male and valid with a value of true. users = [ { name: &apos ...

Discovering the bottom scroll position in an Angular application

I am working on implementing two buttons on an Angular web page that allow the user to quickly scroll to the top and bottom of the page. However, I want to address a scenario where if the user is already at the very top of the page, the "move up" button sh ...

Steps for generating data with Typescript Sequelize model without specifying an id:

Currently, I am utilizing Sequelize in conjunction with Typescript and facing a challenge when attempting to execute the Course.create() method without explicitly specifying an id field. Below is the Course model for reference: import { DataTypes, Model, O ...

error TS2304: The term 'MediaRecorder' is not recognized

How can I add audio recording capability to my Angular application using media recorder? Unfortunately, I am encountering the following error: Error TS2304: 'MediaRecorder' cannot be found If anyone knows a solution for this issue, your help w ...

What is the proper way to include special symbols such as "++" and "#" in a request?

I am facing an issue while trying to make a request to an ASP .NET CORE API from an Angular application using Typescript. Upon sending the request, the API searches in an SQL database for any rows with the specified value. The problem arises when attempt ...

What would happen if I eliminated the preset test cases from a large-scale Angular project?

Currently, in my Angular 5 enterprise application, I have developed numerous components and services using the Angular CLI. Each of these components and services has spec files with the default test case 'Component/Service should be created'. Co ...

I am unable to refresh the table data in Angular

Here is the code that I am currently working with: I am facing an issue where my webpage is not updating its data after performing delete or any other operations. The user list is not being displayed in the data. Despite my attempts, I have been unable to ...

Angular modules are designed to repeat chunks of code in a

Whenever I scroll the page, my function pushes items to an array. However, I am facing an issue where the pushed items are repeating instead of adding new ones. Solution Attempt onScroll(): void { console.log('scrolled'); var i,j,newA ...

How can I transfer information from a map to a child component?

I'm attempting to transfer a variable from a parent component to a child component using React and Typescript. In my Table component (parent), I have the following map. It sets the 'data' variable as the value of the last element in the arr ...

What is the best way to merge an array of objects into a single object?

Is there a way to dynamically convert object1 into object2, considering that the keys like 'apple' and 'water' inside the objects are not static? const object1 = { apple:[ {a:''}, {b:'&apos ...

Exploring the functionality of className using materialUI

Attempting to test whether my component has a specific class is proving challenging. This difficulty stems from the fact that the class is generated using MaterialUI. For instance, I am looking for a class named spinningIconCenter, but in reality, it appea ...

The TypeScript factory class anticipates an intersection

In my code, I have a class factory called pickSomething that generates a specific type based on a key provided from a ClassMap: class A { keya = "a" as const; } class B { keyb = "b" as const; } type ClassMap = { a: A b: B } c ...