Unpacking Constructor with visible arguments

In my constructor, I utilize destructuring to simplify the parameters needed to create an object with default values.

export class PageConfig {
  constructor({
    isSliding = false
  }: {
    isSliding?: boolean;
    getList: (pagingInfo: PagingInfo) => Observable<any>;
  }) {}
}

My goal is to make the properties passed into the constructor public without redeclaring them or using an intermediary object. For example, if a class instanciates my object like this:

class UsersPage {
    config = new pageConfig({ this.getList })    
    getList(pagingInfo: PagingInfo) {
      // do work...
    }
}

I want the config object to expose two things:

config.getList()
config.isSliding

What is the most efficient way to achieve this?

EDIT I've attempted to address this by creating a base class from which both the constructor arguments and the class inherit. However, if I omit the properties in the destructuring, I cannot reference them in the constructor.

For example:

export class PageConfigArgs {
    isSliding?: boolean;
    getList: (pagingInfo: PagingInfo) => Observable<any>;
}

export class PageConfig extends PageConfigArgs {
  constructor({
    isSliding = false
  }: PageConfigArgs ) {
    super();
    this.isSliding = isSliding;
    //this fails since its not declared in the destructuring
    //However I do not want to declare it since it is required
    this.getList = getList;  
  }
}

Answer №1

Developing a solution in TypeScript to automatically transfer properties from an object given to a constructor to the object being created while ensuring safety is not straightforward. Using destructuring does not bring names into scope unless explicitly mentioned, and even if achieved, manual copying of properties is still necessary.

One alternative is to use Object.assign(), mimicking the behavior of destructuring. For example, the constructor could be defined as

constructor(x: X){Object.assign(this, x)}
, which does work at runtime. However, the compiler does not acknowledge the properties set, often leading to warnings.

class FailedPageConfig implements PageConfigArgs { // error!
  // Class 'FailedPageConfig' incorrectly implements interface 'PageConfigArgs'.
  //  Property 'getList' is missing in type 'FailedPageConfig'
  // but required in type 'PageConfigArgs'.
  constructor(config: PageConfigArgs) {
    Object.assign(this, config);
  }
}

This issue can be resolved by using a definite assignment assertion for all supposedly "missing" properties, a declaration originally intended to be avoided.

class OkayPageConfig implements PageConfigArgs { 
  getList!: PageConfigArgs["getList"]; // definite assignment
  constructor(config: PageConfigArgs) {
    Object.assign(this, config);
  }
}

So, what other approaches can be considered?

One option is to create a function that generates class constructors using Object.assign() and utilize a type assertion to instruct the compiler to overlook the verification process:

function ShallowCopyConstructor<T>() {
  return class {
    constructor(x: T) {
      Object.assign(this, x);
    }
  } as new (x: T) => T; // assertion here
}

Subsequently, the generated constructors can be implemented as follows:

export class PageConfigPossiblyUndefinedIsSliding extends ShallowCopyConstructor<
  PageConfigArgs
>() {}

declare const pcfgX: PageConfigPossiblyUndefinedIsSliding;
pcfgX.getList; // Expected: (pagingInfo: PagingInfo) => Observable<any>
pcfgX.isSliding; // Expected: boolean | undefined

By leveraging such an approach, instances of

PageConfigPossiblyUndefinedIsSliding
are guaranteed to possess the specified properties. To address cases where default values are needed, modifications in the form of PageConfig and its constructor can be implemented for a more controlled behavior.


In conclusion, defining your UsersPage class involves careful attention to constructing the PageConfig object. Direct instantiation might not be feasible and could require alternative methods like utilizing helper functions for property copying or implementing type assertions. This complexity might seem overwhelming, but persevering through these challenges will lead to a more robust and safe TypeScript codebase. Good luck!

Link to code

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

Unassigned variable in need of initialization within Angular 2

There seems to be an issue with the two-way data binding not functioning correctly. I am trying to retrieve the data using {user | json}, but I encounter an error when using [(ngModel)] = "user.username". Data Model export interface UserModel { ...

Utilizing Angular 14 and Typescript to fetch JSON data through the URL property in an HTML

Is there a way to specify a local path to a JSON file in HTML, similar to how the src attribute works for an HTML img tag? Imagine something like this: <my-component data-source="localPath"> Here, localPath would point to a local JSON fil ...

Apply criteria to an array based on multiple attribute conditions

Given an array containing parent-child relationships and their corresponding expenses, the task is to filter the list based on parents that have a mix of positive and negative expenses across their children. Parents with only positive or negative child exp ...

Utilizing ES6, accessing the first element of an array of objects

How can I access the values of the first or a specific object in an array based on an index using ES6? arrayOne =[ { child: [ {e1: 'ABCD', e2: 'BCDF'}, {e1: '1234', e2: '5689'}, {e1: 'QAZ ...

Is it possible for a Firestore collection to be deleted when all documents are removed?

I'm facing a dilemma here. When I use code to delete all documents from a Firestore collection, the collection itself disappears as well: this.afs.collection(myCollecton).doc(docId).delete(); However, when I manually delete all documents in the same ...

Encountering challenges with reusing modules in Angular2

I am currently working on an angular2 website with a root module and a sub level module. However, I have noticed that whatever modules I include in the root module must also be re-included in the sub level module, making them not truly reusable. This is w ...

What is the best way to extract data from a proxy in VUE3?

Currently, I am utilizing the ref() function to store data retrieved from Firebase. However, when attempting to filter and retrieve a single record, the outcome is not as expected. Instead of returning a single object, something different is being displaye ...

Continuously converting methods recursively until the array is fully processed

My current code has a method that is not very efficient and does not scale well. The object y is an array consisting of key/value pairs, each containing two properties: 1. A unique string property called name. This value is identified by the childre ...

In the world of Typescript, object-based type inference reigns

I'm grappling with TypeScript to correctly deduce typing in the given code snippet: type Customer = { name: string } type Item = { price: number } const customerConfig = { action: () => [{name: 'Alice'}] as Customer[], } const item ...

Utilizing a method from a separate class in Ionic 2

Having trouble using the takePicture() function from camera.ts in my home.ts. I keep getting an error message saying "No provider for CameraPage!" Any assistance on how to resolve this issue would be greatly appreciated, as I am new to this language and ju ...

Angular router link circles back to its originator

I've been working on a basic login page that transitions to a homepage once the user successfully logs in. So far, I've focused solely on the HTML structure of the login component without implementing any code in the corresponding TypeScript file ...

Base URL for making Http Requests in an Angular application

I am currently working on an angular application that is hosted on a test server running IIS with a .net core backend. The application is set up on a virtual directory, for example www.myTestApp/crm (the actual domain name being fictional). During the buil ...

In JavaScript, loop through an array of arrays and combine them using the concat

If I have an array like [["a", "b"], ["c", "d"]], is there a way to iterate, reduce, map, or join this array in order to get the desired output of ["ac", "ad", "bc", "bd"]? What if the array is structured as [["a", "b"], ["c", "d"], ["e", "f"]]; how can we ...

Navigate to a new tab using this.router.navigate

Is there a way to redirect the user to a specific page with ${id} opening in a new tab, after clicking a button in an angular material dialog box? I want to leave the dialog box open while querying the new page. Currently, the redirect happens but not in a ...

Is it possible for a function within a nodejs module to be defined but display as undefined upon access?

I am currently developing a Discord bot using NodeJS and TypeScript, and I'm facing an issue while trying to import custom modules in a loop with the following code: const eventFiles = fs.readdirSync("./src/events/").filter((file: string) =& ...

Utilizing feature flags for Angular modules to enable lazy loading

Can we dynamically change the lazy loaded module based on a specific flag? For instance, loading module A if the flag is active and module B otherwise. The crucial aspect is that both modules should use the same path. Approach #1 - dynamic loadChildren() ...

Angular is unable to display Observable userdataof any type in an asynchronous task

My home component's HTML is not displaying my userData: <h1 class="display-4">Hello, {{ (userData | async)?.username }}</h1> This is the call in home.component.ts: ngOnInit(): void { this.userData = this.userService.getUser(); } ...

Retrieve highlighted text along with its corresponding tag in ReactJS

my <span class="highlight">highlighted</span> word The text above is showing an example including HTML tags. However, when using window.getSelection(), only the text "my highlighted word" is returned without the surrounding <span& ...

Issue encountered when trying to integrate Angular2 with Visual Studio 2015 Update

Starting my journey with Angular2 in Visual Studio 2015. Following advice from this helpful article. Encountering an issue when running the index.html file, it gets stuck on 'Loading...'. Here are the key configurations and code files being use ...

Undefined error when refreshing Angular page

One particular page on my forum-like website is causing issues with refreshing. In my project, users can log in, view their profiles as well as others'. However, when I refresh a profile page, no data loads from the server and an error appears in the ...