3

I have this code:

export default class MyRandomClass {
  private posFloat32Array?: Float32Array;
  private otherArgument?: number;

  constructor(params:MyRandomClass = {} as MyRandomClass) {
    const {
      posFloat32Array,
      otherArgument,
    } = params;

    this.posFloat32Array = (posFloat32Array !== undefined) ? posFloat32Array : new Float32Array();
    this.otherArgument = (otherArgument !== undefined) ? otherArgument : 0;
  }

  classMethod():void {
    const total = this.posFloat32Array?.length + 3; //error
  }
}

It is not possible that the object is undefined but I do still get the error. My purpose is to have a class that can be constructed with arguments supplied in different ways, so that the output data will always be the same. This is emulating contructor overload as in this example.

I guess there should be a possible way to have a function/class with optional arguments and after tell the compiler that the argument has been actually passed in or if not, the undefined scenario has been managed accordingly.

How can this be handled with optional arguments?

EDIT: Up to what I researched, taking the code example from here, its not possible to make your class variables optional and make the compiler know they will not be undefined and use them in your methods, without making a separated type for the arguments, making this type arguments optional and the class variables not optional, which is kind of verbose if the class is big. I would like to confirm if this is a valid or the best approach to handle optional arguments in typescript classes.

rustyBucketBay
  • 4,320
  • 3
  • 17
  • 47

2 Answers2

1

The compiler is complaining because you have that property defined as optional with the ?. The problem is with your declarations.

Since you have a constructor and the posFloat32Array and otherArgument are always set in the constructor to explicit values, those properties don't need to be marked as optional. You should remove marking these properties as optional.

When would I want class properties to be optional then?

This is a great question! If you did not explicitly implement a constructor, or you are not explicitly settings these values in the constructor, this is when you might want to mark a property as optional. For example, the below class example can be instantiated without those values defined explicitly. Might be a good use case to mark them as optional.

class MyRandomClass {
  private posFloat32Array?: Float32Array;
  private otherArgument?: number;

  classMethod():void {
    const total = this.posFloat32Array?.length ?? 0 + 3;
  }
}
Nitsew
  • 3,612
  • 1
  • 15
  • 20
  • For my specific case, I wanted overload constructor behaviour, so that the constructor gets optional arguments, but so that then I can use those in the class methods without the ts(2532) error. I Achieved that making a different type with the arguments optional for the constructor argument type, and then not marking the class properties as optional (this is with no question mark). A bit verbose but did the work though. (verbose because you need all your class variables question marked for the created type). Wonder if there could be a cleaner or more direct approach for this. – rustyBucketBay Oct 20 '20 at 19:44
  • further detail in my answer to this question with sample code to adress the point I am making, as it is better expressed with the code itself than with words: https://stackoverflow.com/questions/12702548/constructor-overload-in-typescript/64452208#64452208 – rustyBucketBay Oct 20 '20 at 19:52
1

You need to seperate your interface, since the class no longer describes the incoming parameters object. My answer shows is a more elegant way of setting default values. And since you're setting default values, the parameters on the interface are optional, but they are guaranteed within the class (notice where the question marks have moved). This should work for you:

interface MyNotSoRandomInterface {
  posFloat32Array?: Float32Array;
  otherArgument?: number;
}

export default class MyRandomClass {
  private posFloat32Array: Float32Array;
  private otherArgument: number;

  constructor(params:MyNotSoRandomInterface = {} as MyNotSoRandomInterface) {
    const {
      posFloat32Array =  new Float32Array(),
      otherArgument = 0,
    } = params;

    this.posFloat32Array = posFloat32Array;
    this.otherArgument = otherArgument;
  }

  classMethod():void {
    const total = this.posFloat32Array.length + 3; //no errors!
  }
}
Benson
  • 4,181
  • 2
  • 26
  • 44
  • OK thanks a lot! My concern was to clarify this if was the approach when you make arguments optional, as having to kind of declare the type twice makes it a little verbose if the class is big, and that seems to be the point of the question mark. However for the moment it seems that this would be the correct approach :) – rustyBucketBay Jan 18 '21 at 08:30