-3

My Typescript Class contains the method getProductAttributeByName(name: string) which filters the collection defined as parameter of the constructor.

class Product {
    id: string;

    constructor(productDto: IProductDto) {
        this.id = productDto.id;
    }

    getProductAttributeByName(name: string): ProductAttribute {
        // I need productDto (the constructor parameter) here:
        return productDto.productAttributes.filter(x => x.name === name)
    }
}

This is not allowed, so currently I'm doing:

class Product {
    id: string;
    productDto: IProductDto;

    constructor(productDto: IProductDto) {
        this.id = productDto.id;
        this.productDto = productDto;
    }

    getProductAttributeByName(name: string): ProductAttribute {
        return this.productDto.productAttributes.filter(x => x.name === name)
    }
}

Needless to say that this is terrible. I'm exposing a public property which is only needed inside a method, for the only reason that I cannot access the constructor parameter. I also tried, out of desperation, to declare the property as private, like this:

class Product {
    id: string;
    private productDto: IProductDto;

    constructor(productDto: IProductDto) {
        this.id = productDto.id;
        this.productDto = productDto;
    }

    getProductAttributeByName(name: string): ProductAttribute {
        return this.productDto.productAttributes.filter(x => x.name === name)
    }
}

But this doesn't change the fact that the property is still accessible once the object has been initialized:

var product = new Product(myDto);
// product.productDto is accessible!

Is there a way to access a constructor parameter inside a method without having to declare a property that will be publicly accessible?

4
  • Is there a question in your question? Commented Oct 5, 2016 at 8:53
  • 1
    I don't know why the downvotes, but what your currently doing is perfectly fine. Also, @decenze 's answer (and suggestions) is very good as well. Cheers! :) Commented Oct 5, 2016 at 8:55
  • Is product.productDto accessible? I've just tried it in my project (different property) and I get the error 'Property 'privateProp' is private and only accessible within class 'Product''. Not sure what your problem is, what you are doing is fine. Commented Oct 5, 2016 at 8:58
  • Well, it's accessible once ts has been compiled into javascript. Commented Oct 5, 2016 at 9:06

1 Answer 1

6

"Just because my method cannot access a constructor parameter…" is thinking about this in the wrong terms. When instantiating your class, is productDto an important state of your instance? Does the data in productDto hold important information that Product needs during its lifetime? Then you're not merely trying to pass it between your constructor and some method, but that data is part of your object's state. And your object methods use and depend on that state. And object state is always implemented by object properties, so saving productDto on this.productDto is perfect fine and the right way to do it.

But this doesn't change the fact that the property is still accessible once the object has been initialized.

So what? Using TypeScript and the private declaration, TypeScript will ensure that you're not shooting your own foot by trying to access that property from outside code. That's all you need. There's no point in actually trying to enforce non-accessibility. You're just going to bend over backwards for hardly any gain. Many Javascript objects have internal state which you can poke around in if you so wish. That's no problem at all.

It's only a problem if you're actually writing code against these internal properties which aren't supposed to be part of the official API, and that internal implementation changes down the line. Simply don't do that. Again, TypeScript's private helps you enforce exactly that.

this.id = productDto.id;
this.productDto = productDto;

This is pretty redundant. Quite apparently you need productDto.id and productDto later on in other methods. Simply store the entire productDto as a property and access its .id as needed. If you need to expose the id as property on your class, using a get method which returns this.prodctDto.id is probably a sensible idea:

class Product {
    private productDto: IProductDto;

    constructor(productDto: IProductDto) {
        this.productDto = productDto;
    }

    get id(): string {
        return this.productDto.id;
    }

    getProductAttributeByName(name: string): ProductAttribute {
        return this.productDto.productAttributes.filter(x => x.name === name)
    }
}

In general, try designing your classes without writing the constructor first. Write everything but the constructor. Design which internal and external properties your class needs and which properties your methods will get their data from. Then, as the very last step, write your constructor which needs to ensure that the object state is such that all your methods can work as designed. Then the thinking of "passing from constructor to method" obviates itself.

Sign up to request clarification or add additional context in comments.

6 Comments

Alright, I guess what I had in mind is just not possible. Thanks.
Javascript has no enforced "privacy" (without many drawbacks or bending over backwards). The biggest and only problem with that really is too strict thinking that "actual privacy" is somehow really necessary. That's the only issue you really need to get over.
The fact is that we are designing a framework, and we want the classes to be as lean as possible otherwise we'll confuse the developers trying to use them
If you want to make it even more clear, beyond TypeScript's private, that a property is not part of an external API, use a naming convention like ._productDto and document the actual public API properly. If someone is still writing code against the non-public API… well, there are things in life you have no control over…
I'm thinking too much like a C# developer... because that's my background. I guess I'm gonna have to accept the compromise.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.