What is the issue when using TypeScript if my class contains private properties while the object I provide contains public properties?

I am currently facing an issue while attempting to create a typescript class with private properties that are initialized in the constructor using an object. Unfortunately, I keep encountering an error message stating: "error TS2345: Argument of type 'TranslateResponse' is not assignable to parameter of type '{ status: "success" | "failed"; errorCode?: number | undefined; message?: string | undefined; data?: any; }'. 2023-05-30 13:45:24 translator-angular | Property 'status' is private in type 'TranslateResponse' but not in type '{ status: "success" | "failed"; errorCode?: number | undefined; message?: string | undefined; data?: any; }'. I'm confused about the significance of declaring a property as private or public within an object. Although I've come across similar issues concerning interfaces, I don't actually have any interfaces defined in my code.

export class FileTranslatedSuccess {
    
    private newFilePath!: string;
    private newFileName!: string;
    private targetLanguage!: LanguageCode;

    constructor(object: {newFilePath: string, newFileName: string, targetLanguage: LanguageCode}) {
        this.newFilePath = object.newFilePath;
        this.newFileName = object.newFileName;
        this.targetLanguage = object.targetLanguage;
    }

The constructor above takes an object of the following shape:

constructor(object: {
        fileTranslatedSuccess: {[key: string]: FileTranslatedSuccess[]},
        fileTranslatedFailed: {originalFile: string, targetLanguage: LanguageCode, message: string}[] | ""
    }) {
        let keys = Object.keys(object.fileTranslatedSuccess);
        this.fileTranslatedSuccess = {};
        keys.forEach(key => {
            this.fileTranslatedSuccess[key] = [];
            object.fileTranslatedSuccess[key].forEach(fileTranslatedSuccess => {
                this.fileTranslatedSuccess[key].push(new FileTranslatedSuccess(fileTranslatedSuccess));
            });
        });
        if (object.fileTranslatedFailed === "") {
            this.fileTranslatedFailed = "";
        } else {
            this.fileTranslatedFailed = [];
            object.fileTranslatedFailed.forEach(fileTranslatedFailed => {
                if (Array.isArray(this.fileTranslatedFailed)) {
                    this.fileTranslatedFailed.push(new FileTranslatedFailed(fileTranslatedFailed));
                }
            });
        }
    }

This constructor belongs to another object in my codebase. The error occurs when trying to instantiate the FileTranslatedSuccess class. (this.fileTranslatedSuccess[key].push(new FileTranslatedSuccess(fileTranslatedSuccess));). Can someone clarify why setting private properties in the constructor using an object with public properties results in an error?

Answer №1

object.fileTranslatedSuccess[key].forEach(fileTranslatedSuccess => {
    this.fileTranslatedSuccess[key].push(new FileTranslatedSuccess(fileTranslatedSuccess));
});

When working with TypeScript, it assumes that fileTranslatedSuccess is of type FileTranslatedSuccess. During compilation, TypeScript does not dynamically read the real-time value of fileTranslatedSuccess and only recognizes the public properties within the FileTranslatedSuccess class. Even if the values of newFilePath, newFileName, and targetLanguage are valid and accessible during runtime, TypeScript remains unaware.

This creates a dilemma for the TypeScript compiler. On one hand, you indicate that these 3 properties should be private but then proceed to request access to them in order to assign values from one instance to another.

To address this issue, there are several solutions:

  1. Make the properties public.

  2. Create getter functions for each property to retrieve their values. For example:

     export class FileTranslatedSuccess {
    
     private newFilePath!: string;
     private newFileName!: string;
     private targetLanguage!: LanguageCode;
    
     constructor(object: {newFilePath: string, newFileName: string, targetLanguage: LanguageCode}) {
             this.newFilePath = object.newFilePath;
             this.newFileName = object.newFileName;
             this.targetLanguage = object.targetLanguage;
     }
    
     getFilePath(): string {
         return this.newFilePath;
     }
    
     getFileName(): string {
         return this.newFileName;
     }
    
     getTargetLanguage(): string {
         return this.targetLanguage;
     }
    

    }

Subsequently, in your code, you can do something like the following:

object.fileTranslatedSuccess[key].forEach(fileTranslatedSuccess => {
    const filePath = fileTranslatedSuccess.getFilePath();
    const fileName = fileTranslatedSuccess.getFileName();
    const targetLanguage = fileTranslatedSuccess.getTargetLanguage();
    
    this.fileTranslatedSuccess[key].push(new FileTranslatedSuccess({newFilePath: filePath, newFileName: fileName, targetLanguage: targetLanguage}));
});
  1. If object.fileTranslatedSuccess originates from an API call and you aim to instantiate objects as FileTranslatedSuccess types, utilizing interfaces may provide more clarity. By making the 3 properties public in the interface and assigning them accordingly in your constructor, you enhance project readability. Here's a basic untested implementation:

     export interface IFileTranslatedSuccess {
         newFilePath: string;
         newFileName: string;
         targetLanguage: LanguageCode;
     }
    
    
     object.fileTranslatedSuccess[key].forEach((ifileTranslatedSuccess: IFileTranslatedSuccess) => {     
         this.fileTranslatedSuccess[key].push(new FileTranslatedSuccess(ifileTranslatedSuccess));
     });
    

In your FileTranslatedSuccess class, consider implementing:

export class FileTranslatedSuccess {
    
    private newFilePath!: string;
    private newFileName!: string;
    private targetLanguage!: LanguageCode;

    constructor(object: IFileTranslatedSuccess) {
       this.newFilePath = object.newFilePath;
       this.newFileName = object.newFileName;
       this.targetLanguage = object.targetLanguage;
       ...
    }
}

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

Angular 4: preventing button click until form validation is successful

I am facing a situation where I have a form with required fields and 2 buttons: one button is for submitting the form, and the other button is for downloading a file. When the form is not valid, the submit button is disabled until the form becomes valid: ...

Having trouble with ng build optimization error in Angular?

While developing a real-time chat application using Angular 13, I encountered an issue when trying to build the app for testing on my Node.js web server: ng build Every time I run this command, I receive an error in the console. Here is a screenshot of ...

Angular - Automatically create thumbnails for uploaded images and videos

I am working on an Angular application that allows users to upload files. My goal is to create thumbnail images for uploaded images and videos without saving them locally. Instead, I plan to pass them along with the original file data to another API. Howev ...

Can anyone suggest a more efficient method for specifying the type of a collection of react components?

Picture this scenario: you are extracting data from an API and creating a list of Card components to be displayed in a parent component. Your code might resemble the following: function App() { let items = [] // How can I specify the type here to avoid ...

Enhancing an existing Angular1 project to Angular4 while incorporating CSS, Bootstrap, and HTML enhancements

Facing CSS Issues in AngularJs to Angular4 MigrationCurrently in the process of upgrading an AngularJS project to Angular 4, specifically focusing on updating views. However, encountering issues with certain views not displaying the custom CSS from the the ...

Looking to verify the functionality of the router.navigate method when employing relativeTo?

How can we effectively test the router.navigate method to ensure it accepts provided queryParams and navigates to the correct location path? In Component file:-- syncQueryParams() { this.router.navigate([], { relativeTo: this.activatedRoute, ...

Passing variable values in Angular 6

Is there a way to transfer the value of a variable from Component1 to a variable in Component2 without using any template binding? I have two components, Header and Footer. In the Header component, there is a boolean variable called test that I need to pa ...

Display a loading screen while transitioning between routes in Angular 2

Is there a way to implement a loading screen for route changes in Angular 2? ...

Was anticipating 1 argument, however received 5 in TypeScript

When running the code in this part, I expected to receive 0-1 arguments but ended up getting 5 instead. Do you have any suggestions for a solution? Register() { let newUser = new User(this.registerForm.value, newUser.city =this.cityid, ...

Issue with default behavior of infinite scroll in Angular 4

I'm currently working on incorporating infinite scroll into my Angular 4 application. I've carefully followed all the guidelines provided on https://www.npmjs.com/package/ngx-infinite-scroll According to the documentation: By default, the dir ...

Currently, my goal is to create PDFs using Angular

<button class="print" (click)="generatePDF()">Generate PDF</button> Code to Generate PDF generatePDF(): void { const element = document.getElementById('mainPrint') as HTMLElement; const imgWidth = 210; ...

Using TypeScript to work with JSON fields that include the '@' symbol

While working on an Angular project with TypeScript, I am facing a challenge of displaying certain JSON fields obtained from a POST request to the user. One of the fields begins with the '@' symbol, which is a reserved word in Angular causing th ...

VIDEOJS ERROR: A peculiar mistake has occurred. TypeError: The property 'value' cannot be read since it is undefined in the context of

Recently, I came across a fascinating plugin called videojs-thumbnails for video.js, and I'm eager to incorporate it into my angular component. However, I keep encountering an error that says: VIDEOJS: ERROR: TypeError: Cannot read property 'val ...

Having difficulty accessing the 'makeCurrent' property of an undefined object in Angular mobile application

I have followed the steps outlined in the Angular mobile toolkit guide found at https://github.com/angular/mobile-toolkit/blob/master/guides/cli-setup.md My Node version is v4.4.3 NPM version is 2.15.1 The issue arises when I run the command $ ng serve, ...

Troubleshooting problems encountered in Nest.js due to modifications made within a service.ts file

I'm currently working on a Nest.js project and here is the content of the automobile.service.ts file: import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Car } from './enti ...

Tips for successfully mocking axios.get in Jest and passing AxiosPromise type value

I attempted to simulate the axios.get() function using the code below, however TypeScript is returning an error stating "argument of type '{ data: expectedResult }' is not assignable to parameter of type 'AxiosPromise<{}>'". Can ...

Send the latest cell parameters from the CellRendererFramework element to the main grid component

Within ag-grid, I am utilizing the cellRendererFramework to render a specific cell. By accessing the params property, I can retrieve the values of the cell from the parent grid component. However, I now have the need to update these params from my cellRend ...

Error Message: The Query<DocumentData> type cannot be assigned to the DocumentReference<DocumentData> parameter

Currently, I am attempting to execute a query against Firestore data. Here is my code snippet: import { collection, getDoc, query, where } from "firebase/firestore"; import { db } from "../../utils/firebaseConfig"; const getQuery = a ...

Is it feasible to mock a defined function in Typescript for a unit test scenario?

Currently, I am working on typescript code that compiles into javascript, gets bundled with rollup, and is utilized by a framework. This framework exposes a library to me in the global scope, taking the form of a function: fun({ prop1: number, ...

Using an enum with [routerlink] in Angular 7 is a great way to navigate

Enum Example: export enum InternalLinks { Home = '/home', About = '/about' } In the HTML of my CustomComponent, I have this: <div class="link-container text-right"> <a [routerLink]="InternalLinks.About" class="text-b ...