Search code examples
javascripttypescriptpass-by-referencejsxpass-by-value

Typescript/JSX - Assign an instance of a class by reference


Essentially, I want to be able to access an object's property by reference. Take a look at the code below;

class Point{
  x:number;
  y:number;
  constructor(x,y)
  {
    this.x=x;
    this.y=y;
  }
}

const a = { first: new Point(8,9), second: new Point(10,12) };
let someBool = true;

function modifyProperty(a) {
  let c = someBool? a.first: a.second;

  let newPoint = new Point(0,0);
  c = newPoint;         // Doesn't work

  someBool = !someBool;
}

modifyProperty(a);
console.log(a.first);

In this example, whenever I call modifyProperty() I want to alternate between changing one of the two properties in 'a'.

However, when I assign 'c' to either 'a.first' or 'a.second', it only passes by value. The only way I could think to fix this is by making the property itself an object, like this:

 const a = { first: {value: new Point(8,9)}, second: {value: new Point(10,12)} };

And then I would just call c.value = newPoint instead. This would work, but it's not a good solution, since you'd have to do this for every property in an object.

Is there no way better way to get these properties by reference? I know JS only supports pass-by-reference for objects and arrays, but what about instances of classes?

I know when Babel converts a class to normal Javascript they're treated like functions, but a function is not a primitive type - it's an object that is callable, so doesn't this work, and what would be a solution?


Solution

  • However, when I assign 'c' to either 'a.first' or 'a.second', it only passes by value

    Yes, assignment always changes the value of the thing on the left side of =, there is no way to change it in Javascript or TypeScript.

    One workaround is to use property name together with the object to which the property belongs, instead of reference:

    type Pair<T> = { first: T, second: T }
    
    function modifyProperty(a: Pair<Point>) {
        let c: keyof Pair<Point> = someBool? 'first' : 'second'; 
        // keyof Pair<Point> type annotation means 
        // that only property names of Pair could be assigned to c  
    
        let newPoint = new Point(0,0);
        a[c] = newPoint;         
    
        someBool = !someBool;
    }