Object is possibly 'undefined'.ts(2532) with optional arguments

1.4k Views Asked by At

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.

2

There are 2 best solutions below

1
On BEST ANSWER

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!
  }
}
2
On

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;
  }
}