Create a class with additional attributes to support different types of options

I define a set of options represented by strings:

export type Category = 'people' | 'projects' | 'topics' | 'tools'

An index is declared as follows:

interface Entry {
  ...
}
type IPostEntryIndex = {
  [name in Category]: Entry
}

How can I create class properties that correspond to the category names?

const categories: Category[] = ['people', 'projects', 'topics', 'tools']

class PostEntryIndex implements IPostEntryIndex {
  // What needs to be included here so that `PostEntryIndex` has a property 
  // for each category listed in Category?

  constructor () {
    categories.map(cat => this[cat] = new Entry())
  }
}

Note: While I could explicitly declare the categories, I am seeking a more efficient solution that doesn't require manual updates when a new category is added. Keeping categories array aligned with Category would also be ideal. Perhaps utilizing an enum could help achieve this.

Answer №1

There isn't a specific syntax that allows you to declare multiple properties in a class all at once. You can create an index signature, but not a union of string literals. Of course, you could manually add each property, but I assume you're looking for a more efficient solution.

One workaround is to use declaration merging to incorporate the properties into the class instance's interface. By defining a class like class PostEntryIndex {}, you generate a value named PostEntryIndex that represents a class constructor, as well as an interface also named PostEntryIndex which mirrors the class structure. With interface merging, you can easily append any desired properties:

interface PostEntryIndex extends IPostEntryIndex { }
class PostEntryIndex {
  constructor() {
    categories.map(cat => this[cat] = new Entry())
  }
}

It's important to note that utilizing this method bypasses strict class property initialization checks enforced by --strict mode. This means you won't receive warnings from the compiler regarding uninitialized properties, although in this context using categories does initialize the necessary properties.

In addition, after merging the interfaces in this manner, the implements clause becomes somewhat redundant, so it has been omitted here. (In truth, implements clauses are often unnecessary due to TypeScript's structural type system allowing objects with compatible structures to be used interchangeably.)

To test if everything functions correctly:

const pei = new PostEntryIndex();
pei.projects; // Entry

Seems to be working fine. Hopefully this information proves useful to you; best of luck!

Playground link for code demonstration

Answer №2

This code snippet is compatible with https://www.typescriptlang.org/play/

export type CategoryList = 'people' | 'projects' | 'topics' | 'tools'

class Entry {
}

type IPostEntryIndex = {
  [item in CategoryList]: Entry
}

const categoriesList: CategoryList[] = ['people', 'projects', 'topics', 'tools']

class PostEntryIndex implements IPostEntryIndex
{
  people: any;
  projects: any;
  topics: any;
  tools: any;

  constructor () {
    categoriesList.map(category => this[category] = new Entry())
  }
}

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

To collapse a div in an HTML Angular environment, the button must be clicked twice

A series of divs in my code are currently grouped together with expand and collapse functionality. It works well, except for the fact that I have to click a button twice in order to open another div. Initially, the first click only collapses the first div. ...

When the value is empty, MUI Autocomplete will highlight all items

I have encountered a specific issue. I am working on developing a custom Autocomplete Component for filtering purposes. However, I recently came across the following Warning. MUI: The value provided to Autocomplete is invalid. None of the options matc ...

Learn how to utilize the "is" status in Postma within your code, even when this particular status is not included in the response

Service.ts Upon invoking this function, I receive a JSON response similar to the following: public signupuser(user: Users): Observable<boolean> { let headers = new Headers(); headers.append('Content-Type', 'application/json&a ...

Initiating a GET request to execute an SQL query with specified parameters

Let me provide some background information. I am currently using Angular for the frontend and Express for the backend, while also learning how to effectively utilize both technologies. In my application, there is a parent component that generates a group ...

Incorporating Google Pay functionality within Angular applications

I have been attempting to incorporate Google Pay into my Angular project, but I am struggling to find reliable resources. My main issue revolves around the following code... <script async src="https://pay.google.com/gp/p/js/pay.js" onloa ...

Incorrect typings being output by rxjs map

combineLatest([of(1), of('test')]).pipe( map(([myNumber, myString]) => { return [myNumber, myString]; }), map(([myNewNumber, myNewString]) => { const test = myNewString.length; }) ); Property 'length' does not ...

Potential Null Object in Typescript Mongoose: A Concern

Encountering an issue while attempting to locate my user model: Object is possibly 'null'. I would like to find a solution that does not involve suppressing TypeScript's strict rule. const { email, password } = req.body; const user = awai ...

Tips on sorting a FileList object selected by a directory picker in JavaScript/TypeScript

I need to filter or eliminate certain files from a FileList object that I obtained from a directory chooser. <input type="file" accept="image/*" webkitdirectory directory multiple> Within my .ts file: public fileChangeListener($event: any) { let ...

Issue occurred while trying to render a React component with Typescript and WebPack

I am in the process of creating a basic React component that simply displays a page saying Hello. However, I'm encountering an error in my console. My compiler of choice is TypeScript. To set up my project, I am following this guide: https://github.co ...

Problems arising from the layout of the PrimeNG DataView component when used alongside Prime

I've been working with a PrimeNG DataView component that requires the use of PrimeFlex's flex grid CSS classes to set up the grid structure. One of their examples includes the following instructions: When in grid mode, the ng-template element ...

What is the most efficient way to simultaneously check multiple variables for undefined values?

Before executing my code, I need to ensure that none of the variables in a given list are undefined. In the code snippet below, there are 4 variables with uncertain values. While I can manually check variables a and b to satisfy TypeScript's requirem ...

Encountering an issue with top-level await in Angular 17 when utilizing pdfjs-dist module

While using the Pdfjs library, I encountered an error message that reads: Top-level await is not available in the configured target environment ("chrome119.0", "edge119.0", "firefox115.0", "ios16.0", "safari16.0" + 7 overrides) /****/ webpack_exports = g ...

What is the best way to accurately parse a Date object within a TypeScript class when the HttpClient mapping is not working correctly?

Task.ts: export class Task { name: string; dueDate: Date; } tasks.service.ts: @Injectable() export class TasksService { constructor(private http: HttpClient) { } getTasks(): Observable<Task[]> { return this.http.get<Ta ...

Exploring URL Parameters in Angular Unit Testing

My goal is to execute a test to check for the presence of a specific string in URL parameters. Inside my TypeScript file, I have defined the following method: checkURLParams() { if (this.route.parent) { this.route.parent.params.subscribe((params) ...

Is there a way to go back to the previous URL in Angular 14?

For instance, suppose I have a URL www.mywebsite.com/a/b/c and I wish to redirect it to www.mywebsite.com/a/b I attempted using route.navigate(['..']) but it seems to be outdated and does not result in any action. ...

Component re-rendering and initializing useReducer

I made some revisions to this post. Initially, I shared the entire problem with my architecture and later updated it to focus directly on the issue at hand in order to make it easier for the community to provide assistance. You can now jump straight to the ...

Discovering the generic parameter in the return type using TypeScript

I am struggling with a specific issue export type AppThunk<ReturnType> = ThunkAction< ReturnType, RootState, unknown, Action<string> >; After implementing the above code snippet export const loadCourse = (id: string): AppThunk ...

Is there a way to specifically target the MUI paper component within the select style without relying on the SX props?

I have been experimenting with styling the Select MUI component using the styled function. I am looking to create a reusable style and move away from using sx. Despite trying various methods, I am struggling to identify the correct class in order to direct ...

Avoid using dot notation with objects and instead use `const` for declaring variables for more

interface obj { bar: string } function randomFunction() { let foo: obj = { bar: "" } foo.bar = "hip" } let snack: obj = { bar: "" } snack.bar = "hop" Upon transcompiling, a warning from tslint pops up: Identifier 'foo' is never reassi ...

How to implement a responsive menu using the onPress attribute of TouchableOpacity

Looking to implement a profile picture upload feature with the ability to choose between getting an image from the camera (using getMediaFromCamera) or selecting one from the gallery (using getMediaFromImageLibrary). I currently have a TouchableOpacity set ...