Kjeld
Kjeld

Reputation: 470

Typescript: unable to initialize property from object property in constructor

In a Angular application I have defined a typescript class Foo and a class Product.

export class Product {

    title: string

    constructor(title: string) {
    
        this.title = title
    }
}

and

import { Product } from ... // importing Product
export class Foo {

    product: Product
    productTitle: string

    constructor(product: Product) {
    
        this.product = product  // works fine, I can access product.title on Foo object
        this.productTitle = product.title   // productTitle is null
    }
}

The class Foo is used when a HTTP response of remote objects from a REST call is translated into an array of Foo objects.

this.httpHelper.post('/api/get/foos', form).subscribe(response => {
    if (response) {
        this.foos = response.resultObject['remoteFoo'] as Foo[]
        ...

I would like to know, why the property product in the Foo objects is initialized just fine, but productTitle resolves to null?

I want Foo to just have the productTitle, and not a product like its remote equivalent has.

Cheers, Kjeld

SOLUTION: with help of @Chris Hamilton's answers here below.

I created an AbstractFoo and a RemoteFoo class, and had Foo and RemoteFoo both extend from AbstractFoo. The latter contains all common properties. Foo has a productTitle property, and a constructor taking a RemoteFoo. And RemoteFoo has a product property (which in turn is a Product class, having a title property).

const remoteFoos: RemoteFoo[] = response.resultObject['remoteFoos'];

... gets a collection of RemoteFoo objects, and

this.foos = remoteFoos.map((remoteFoo) => new Foo(remoteFoo));

... creates a collection of local Foo objects. The constructor of Foo initializes its productTitle with remoteFoo.product.title .

Upvotes: 0

Views: 322

Answers (1)

Chris Hamilton
Chris Hamilton

Reputation: 10994

My guess is you think that as Foo[] calls the Foo constructor. It does not, that's a typecast only used for linting and type checking when compiling.

You'll need to call the constructor for each element of the array. You can use the map method of Array for this.

Assuming response.resultObject['remoteFoo'] is an array of Product:

this.httpHelper.post('/api/get/foos', form).subscribe(response => {
    if (response) {
        const products: Product[] = response.resultObject['remoteFoo'];
        this.foos = products.map((foo) => new Foo(foo));

Although when you said "property product in the Foo objects is initialized just fine" I'm guessing that the products are actually nested in an object.

So maybe:

this.httpHelper.post('/api/get/foos', form).subscribe(response => {
    if (response) {
        const products: { product: Product }[] = response.resultObject['remoteFoo'];
        this.foos = products.map((foo) => new Foo(foo.product));

Depends on what response.resultObject['remoteFoo']; actually is.


Since you said response.resultObject['remoteFoo']; is of type Foo[], the second solution would work, but this is more concise:

this.httpHelper.post('/api/get/foos', form).subscribe(response => {
    if (response) {
        const foos: Foo[] = response.resultObject['remoteFoo'];
        this.foos = foos.map((foo) => new Foo(foo.product));

Upvotes: 1

Related Questions