Exploring TypeScript: A Study on Interfaces and Abstraction

I am working with TypeScript and have created four different entities (models) as shown below:

Base model definition:

export interface BaseModel {
  id: string;
  entityId: string;
  entityName: string;
}

Child Model 1:

import { BaseModel } from './base-model';

export interface ChildModel1 extends BaseModel {
  commentId: string;
  authorName: string;
}

Child Model 2:

import { BaseModel } from './base-model';

export interface ChildModel2 extends BaseModel {
  authorName: string;
}

Child Model 3:

import { BaseModel } from './base-model';

export interface ChildModel3 extends BaseModel {
  operationType: string;
}

Now, I want to achieve generalization in my component similar to what is possible in Java.

For example, how can I store objects of different types like ChildModel1, ChildModel2, ChildModel3 within an array named models?

UPDATE:

Here is a screenshot displaying the error I encountered in Visual Studio Code.

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

Answer №1

Affirmative, it is indeed possible to achieve this task. Your issue likely arises from utilizing a "fresh" object literal (i.e., one that has not been previously assigned to any variable) and assigning it to a specific type variable in TypeScript. In such cases, TypeScript employs excess property checks to warn you if unexpected properties are added. While types in TypeScript are typically open/extendable/generalizable, they assume a closed/exact nature in instances like this because committing such actions is often erroneous.

const excessPropertyErrors: BaseClass[] = [
  { id: "a", entityId: "b", entityName: "c', commentId: "d", authorName: "e' },
  { id: "f", entityId: "g", entityName: "h", authorName: "i' },
  { id: "j", entityId: "k", entityName: "l", operationType: "m' }
]; // error! encountering issues with excess property checks here

To address this concern, several strategies can be employed.


One approach involves explicitly listing the subclasses expected. The types BaseClass and

BaseClass | ChildClass1 | ChildClass2 | ChildClass3
share structural similarities but vary in their treatment towards "extra" properties:

const explicitlyMentionSubclasses: 
 Array<BaseClass | ChildClass1 | ChildClass2 | ChildClass3> = [
  { id: "a", entityId: "b", entityName: "c", commentId: "d", authorName: "e" },
  { id: "f", entityId: "g", entityName: "h", authorName: "i" },
  { id: "j", entityId: "k", entityName: "l", operationType: "m" }
]; // acceptable

This method would still trigger an excess property error if operationType is misspelled, warranting additional caution. Nevertheless, embedding subclass information within the variable type may impose certain limitations.


Another viable option entails assigning the fresh object literal to variables annotated with the desired subclass type, subsequently populating your array with these variables:

const childClass1: ChildClass1 = 
  { id: "a", entityId: "b", entityName: "c", commentId: "d", authorName: "e" };
const childClass2: ChildClass2 = 
  { id: "f", entityId: "g", entityName: "h", authorName: "i" };
const childClass3: ChildClass3 = 
  { id: "j", entityId: "k", entityName: "l", operationType: "m" };
const individualElements: BaseClass[] = [childClass1, childClass2, childClass3]; // appropriate

This represents one of the safest methodologies available, ensuring that each variable childClass1, childClass2, and childClass3 undergo relevant subclass constraints and excess property scrutiny.

... (continues)

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

TypeScript: "The type is generic and can only be accessed for reading." - Error code 2862

Consider this sample JS function that requires type annotations: const remap = (obj) => { const mapped = {}; Object.keys(obj).forEach((key) => { mapped[key] = !!key; }); return mapped; }; I am attempting to add types using generics (in ...

Step-by-step guide on developing an AngularJs provider using TypeScript

As I've developed a Directive that incorporates various Css classes, it would greatly enhance its flexibility if the Css classes could be configured at Application start within the config section. I believe utilizing a provider is the appropriate appr ...

"Conceal Digits with SweetAlert2's Number Mask

Could you assist me in adding a number mask to an input field in sweetalert2? Here is my code: onClick(btn) { let code2_fa = ''; if (JSON.parse(localStorage.getItem('user')).password.two_factors.is_active) { swal({ ...

Leveraging Class Types with Generics

Take a look at this example: https://www.typescriptlang.org/docs/handbook/2/generics.html#using-class-types-in-generics To make it work, I just need to call a static method before instantiation. Let's adjust the example like this: class BeeKeeper { ...

The Angular map function is throwing an error stating "undefined is not a function"

Currently, I'm diving into this fantastic tutorial on Angular 2 and VS Code. Following the steps, I set up a db.json server to experiment with an API using test data structured as follows: { "articles": [{ "id": 1, "name": "Wa ...

Tips for importing bootstrap scss efficiently in an angular project to prevent style duplication

Is there a way to optimize an Angular project for utilizing Bootstrap's mixins and variables without constantly importing the styles in every component? Currently, the project I'm working on imports the variables.scss file multiple times due to u ...

Creating a Higher Order Component (HOC) for your Next.js page

Upon running the following code, I encountered an error message Error: The default export is not a React Component in page: "/" pages/index.tsx import React, { useState, useRef } from "react"; import type { NextPage } from "next&q ...

What is the best way to make an Angular Material checkbox respond to a programmatic change in value within a reactive form?

I have implemented a dynamic angular form that allows users to add rows using a button. I am currently working on adding functionality to select all rows. Each row includes a checkbox that toggles the value in the object between T and F. If all checkboxes ...

Having trouble executing ng build --prod in Azure CICD pipelines

Having trouble setting up my application's CI/CD in Azure as the build process keeps failing. I've gone through my YAML configuration and tried multiple solutions found online, but it still doesn't work. This is the YAML setup I have: ...

Navigating to a specific section

Just a heads up: I'm relatively new to Angular, so there's a possibility that my understanding might be off and therefore my question may not make sense. I've recently started working on an application that requires several intricate featur ...

Maintain synchrony of the state with swiftly unfolding occurrences

I developed a custom hook to keep track of a state variable that increments based on the number of socket events received. However, when I tested by sending 10 simultaneous events, the total value of the state variable ended up being 6, 7, or 8 instead of ...

"Encountering a Cypress Angular error: CypressError with the message 'Timed out retrying: Expected content was not

During my Cypress test run, I encountered an error message on the last step (click) which stated: Timed out retrying: Expected to find element: .button-darkblue, but never found it. Here is the code snippet: describe('Test Login', () => { i ...

Combining multiple arrays of objects using multiple keys with Angular 9 and Typescript

I have two JSON objects (displayed here with JSON.stringify(array of objects)) GPRows data is [ { "shopName":"Testing One", "state":"NSW", "yearMonth":"20203", "id& ...

An error occurred while attempting to set up Next-auth in the process of developing

In my Next.js app, I have implemented next-auth for authentication. During local development, everything works fine with 'npm install' and 'npm run dev', but when I try to build the project, I encounter this error message: ./node_modul ...

The scope of the inferred type parameter in the generic TypeScript function is overly broad

I'm currently working on creating a function that takes in another function (a React component) as an argument and then returns a related function. My goal is to define specific requirements for the input function, ensuring that it accepts certain pr ...

Next.js API routes encountering 404 error

I am encountering an issue with calling my route API (404) in my new nextjs project. The route API can be found at src/app/api/speed.js Within my page src/app/page.tsx, I have the following code snippet: fetch("api/speed").then(res=>res.json ...

I'm working with Angular 12, Bootstrap 5, and ngPrime, and I'm looking to overlap a p-dialog with another element in my project

Is there a way in Angular 12 with Bootstrap 5 using ngPrime to overlap a p-dialog over any other element without using z-index and CSS, solely relying on PrimeNG? I have tried using z-index with: .my-class{ z-index: 2147483647 !important; } However, ...

Ionic causing delay in updating ngModel value in Angular 2

My ion-searchbar is set up like this: <ion-searchbar [(ngModel)]="searchQuery" (keyup.enter)="search();"></ion-searchbar> In the typescript file, the searchQuery variable is defined as follows: export class SearchPage { searchQuery: string ...

Adding a custom role in Angular TypeScript in Microsoft AppInsights is a straightforward process that can provide valuable

I have an angular project where I am looking to incorporate AppInsight with custom telemetry (role). The project is built in Angular using TypeScript, and I successfully integrated appinsights by following this tutorial. However, when attempting to add cus ...

A method for increasing a counter using only an instance of a class or function without accessing its methods or properties in Javascript

Looking at the task ahead, let increment = new Increment(); I have been tasked with creating a Javascript class or function called Increment in order to achieve the following: console.log(`${increment}`) // should output 1 console.log(`${increment}`); ...