Leaky abstraction with setters and getters in js/ts

I am working on a game. Because I don’t want to marry frameworks, I wrote an abstraction for the graphics engine and am now trying to shoehorn three.js into it.

I am working with gl-matrix for vector math (using vec3, typed arrays), three.js has its own vector classes (using {x:number, y:number, z:number}). My interface for a 3d object looks as follows:

interface Thing{
    ...
    position:vec3
}

and my implementation looks like this:

class ThreeJsThing implements Thing{
    ...
    set position(p:vec3){
        this.mesh.position.set(p[0], p[1], p[2]) // [,,] -> {xyz}
    }
    get position(){
        let p = this.mesh.position
        return vec3.fromValues(p.x, p.y, p.z) // {xyz} -> [,,]
    }
}

Now it’s all fun and games until someone tries to do:

let myThing = new ThreeJsThing()
myThing.position[1] = 5 // only changes a temporary copy that is returned by the getter

And with gl-matrix this is especially a problem because it uses output parameters for performance reasons, internally doing that array assignment above:

vec3.add(myThing.position, a, b)

I know how to work around this problem because I am (now) aware of it, but other contributors are probably also going to choke on this, especially since it fails silently. Just from a clean code point of view, I can’t really pinpoint where I used anti-patterns or bad design or something. I find ThreeJsThing to be as faithful to the interface as possible. I have some suspicions:

  • maybe this is just a general problem with set and get and they should be avoided?
  • maybe set and get should not do copies and only accept/return and internally work with references of the same type?
  • output parameters are frowned upon (but then myThing.position[1] = 5 is still a problem)

Any advice appreciated.