Generic Typescript Placeholder Design

Imagine you have the following data:

const dataA = {
  name: "John",
  age: 25,
  attributes: {specificA: "hello", specificA2: 14, nonspecific:"Well"},
}

const dataB = {
  name: "Lisa",
  age: 38,
  attributes: {specificB: "hello", someMoreSpecificStuff: true, nonspecific:"Hope this"},
}

const dataC = {
  name: "Peter",
  age: 60,
  attributes: {specificC: "hello", couldBeAnyName: "Oh My", nonspecific:"makes sense"},
}

Some components will only access basic information like name and age. Others will access general information as well as shared properties with different values (attributes.nonspecific). Some components will exclusively work with one type of data.

To handle this, I have defined the following structure:

const dataA: MyDataType<A> = {
  name: "John",
  age: 25,
  attributes: {specificA: "hello", specificA2: 14, nonspecific:"Well"},
}

const dataB: MyDataType<B> = {
  name: "Lisa",
  age: 38,
  attributes: {specificB: "hello", someMoreSpecificStuff: true, nonspecific:"Hope this"},
}

const dataC:MyDataType<C> = {
  name: "Peter",
  age: 60,
  attributes: {couldBeAnything: "Oh My", nonspecific:"makes sense"},
}

type MyDataType<T extends A | B | C> = {
  name: string;
  age: number;
  attributes: T
}

type A = {
  specificA: string;
  specificA2: number;
  nonspecific: string;
}

type B = {
  specificB: string;
  someMoreSpecificStuff: true;
  nonspecific: string;
}

type C = {
  couldBeAnything: string;
  nonspecific: string;
}

While this approach works, it becomes cumbersome to specify all data types in every component:

interface ForMyGeneralComponent{
  data: MyDataType<A | B | C>
}

It would be more desirable to use a generic type instead:

interface ForMyGeneralComponent{
      data: MyDataType<GenericType>
    }

and declare elsewhere that GenericType can be either A, B, or C.

This simplification would make the code more readable, especially when dealing with multiple data types.

Typescript playground

Answer №1

Perhaps I am not fully grasping the scenario you are describing.
It could be that you are looking to define a new category for all your characteristics for instance.

const MyCharacteristics = X | Y | Z;

const MyInfoType<U extends MyCharacteristics> = {
  title: string;
  value: number;
  characteristics: U
}

interface ForMySpecificSection{
  details: MyInfoType<MyCharacteristics>
}

Answer №2

It seems like what I'm aiming for is to construct a versatile component that can accommodate all subclasses without discrimination, ensuring that only type-independent properties are utilized in these components.

In response to your note on the other thread, you might be overcomplicating things unnecessarily! If some components can handle any subtype without the need for a generic or union, all you have to do is define the common elements.

type GeneralType = {
  name: string;
  age: number;
  attributes: {
    nonspecific: string;
  }
}

This doesn't necessarily need to be a generic, but it could be converted into one to simplify creating specific versions. You can assign a default value to the generic variable when no other value is specified. We aim to have a type that defaults to the GeneralType but can also generate data for A, B, and so on.

I suggest including only the properties that change within the generic variable. For consistency, I would exclude nonspecific: string from the generic part as it remains constant.

In this scenario, the generic Extra encompasses all additional attributes beyond nonspecific.

type MyDataType<Extra extends {} = {}> = {
  name: string;
  age: number;
  attributes: Extra & {
    nonspecific: string;
  }
}

If not specified, the general case will automatically use an empty object as the default (no extra properties).

interface ForMyGeneralComponent {
  data: MyDataType;
}
const dataGeneral: MyDataType = {
  name: "Peter",
  age: 60,
  attributes: {nonspecific:"makes sense"},
}

The specifics of your cases remain largely unchanged, such as const dataA: MyDataType<A>, but now the inclusion of nonspecific in A, B, and C is unnecessary.

Explore Typescript 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

return to the original secured page based on the most recent language preference

I'm facing an issue with a logical redirection that needs to redirect users to the previous protected page after login. The login functionality is implemented using my custom login page and Google Credentials. Additionally, I have set up a multilingu ...

Unable to bring in a TypeScript library that was downloaded from a GitHub fork repository

Currently, I am working on developing a GitHub app using the probot library. However, I have encountered an obstacle as outlined in this particular issue. It seems that probot does not offer support for ESM modules, which are crucial for my app to function ...

Incorporating aws-sdk into Angular 2 for enhanced functionality

I'm currently working on integrating my Angular2 application with an s3 bucket on my AWS account for reading and writing data. In the past, we used the aws-sdk in AngularJS (and most other projects), so I assumed that the same would apply to Angular2 ...

How to utilize *ngFor alongside the async pipe for conditional rendering in Angular 8 HTML

.html <ng-container *ngFor="let contact of listContact | async; let index = index;"> <h6 class="title" *ngIf="contact && contact['type']"> {{contact['type']}} </h6> <div> {{conta ...

NGXS Alert: Unable to resolve parameters for TranslationEditorState: (?)

I'm currently implementing NGXS for state management within my Angular 9 application. I've encountered a specific issue where any attempt at dependency injection in one of the state classes results in an error message stating "Error: Can't r ...

Incorporating a JavaScript file into Angular

I'm looking to incorporate a new feature from this library on GitHub into my Angular project, which will enhance my ChartJS graph. @ViewChild('myChart') myChart: ElementRef; myChartBis: Chart; .... .... const ctx = this.myChart.nativeEleme ...

Setting up a Typescript project using webpack

Greetings! I am looking to set up Typescript with composite config and webpack (everything worked fine with just a single tsconfig.json). I must admit that I am new to TypeScript and have been more familiar with JavaScript. My main issue is getting the des ...

Tips for utilizing the "??=" syntax in Typescript

let x; x ??= 'abc' console.log(x); // abc Running the code above in the browser console does not cause any issues. However, when attempting to run it in TypeScript, an error is thrown. SyntaxError: Unexpected token '??=' Here is my c ...

What is the best way for me to generate a fresh object?

In one of my components, I have implemented a feature where clicking on an image toggles a boolean variable to show or hide a menu. The HTML structure for this functionality is as follows: <img src="../../assets/image/dropdown.png" class="dropdown-imag ...

There are no functions or classes returned when using NPM Link with the module

Welcome. Whenever I run npm link ../folder/ToFolder, it works as expected. However, when I attempt to import any function, nothing is returned. A clearer explanation I have tried importing a module that I created from another folder using npm link. When ...

Issue with `rxjs/Subject.d.ts`: The class `Subject<T>` is incorrectly extending the base class `Observable<T>`

I found a sample template code in this helpful tutorial and followed these two steps to get started - npm install // everything went smoothly, created node_modules folder with all dependencies npm start // encountered an error as shown below- node_mo ...

leveraging the tsconfig path for the source directory in the Next.js Image component

I'm attempting to store the path of my assets folder in the tsconfig file and then use it in the src attribute of the Image component, but for some reason it's unable to locate the address! This is what's in my tsconfig.js file: "paths ...

Tips for prohibiting the use of "any" in TypeScript declarations and interfaces

I've set the "noImplicitAny": true, flag in tsconfig.json and "@typescript-eslint/no-explicit-any": 2, for eslint, but they aren't catching instances like type BadInterface { property: any } Is there a way to configure tsco ...

Retrieve a variable in a child component by passing it down from the parent component and triggering it from the parent

I'm struggling to grasp this concept. In my current scenario, I pass two variables to a component like this: <app-selectcomp [plid]="plid" [codeId]="selectedCode" (notify)="getCompFromChild($event)"></app-select ...

The guidelines specified in the root `.eslintrc.json` file of an NX workspace do not carry over to the project-level `.eslintrc.json` file

In my main .eslintrc.json file, I have set up some rules. This file contains: { "root": true, "ignorePatterns": ["**/*"], "plugins": ["@nrwl/nx", "react", "@typescript-eslint", &qu ...

Finding a solution for duplicate date selections in NextJS using react-calendar

I am currently working on a calendar component using NextJS, typescript, tailwindcss, and the react-calendar library. I have encountered an issue with duplicate dates appearing in the calendar when selecting a date range. Although I have managed to handle ...

What is the best way to reference a component variable property within its template without explicitly stating the variable name?

Suppose my component is managing an instance of the following class: class Person { firstName: string; lastName: string; age: number; } Is there a way to directly reference its properties in the template like this: <p>{{firstName}}</p> & ...

Troubleshooting the NullInjectorError in Angular - Service Provider Missing?

I'm facing an issue in my code where I have buttons that should trigger pop-ups displaying details as a list when clicked. However, every time I click the buttons, I encounter the error mentioned below. It seems like I am unable to access the desired ...

Angular 5 APP_INITIALIZER: Provider parse error - Cyclic dependency instantiation not possible

I am utilizing the APP_INITIALIZER token to execute a task upon page load before my Angular application is initialized. The service responsible for this functionality relies on another service located within my CoreModule. The issue at hand seems to be ab ...

Ways to Halt observable.timer in Angular 2

As I work on Angular2's Component, I am currently implementing the following functions: export class MypageEditComponent { ngOnInit() { this.timer = Observable.timer(100, 100); this.timer.subscribe(t => { this.setFormData(); } ...