0

I made a Vector class but I have some problem with the syntax.

This is my code:

export class Vector {
  x: number;
  y: number;

  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  add(v: Vector) {
    var x: number, y: number;

    for (var component in this) {
      component == "x"
        ? (x = this[component] + v[component])
        : (y = this[component] + v[component]);
    }

    return new Vector(x, y);
  }
}

Here is the syntax problem I have:

enter image description here

As you see "x" and "y" in line "return new Vector(x,y)" say "Variable 'x' is used before being assigned"... And for the "v[component]" says "Type 'Extract<keyof this, string>' cannot be used to index type 'Vector'."

I don't know what I have done wrong, the code works but I want to write it correctly.

3
  • 5
    Why not the simple and straightforward way? The loop just complicates things without providing any benefit as far as I can see... Dynamic loops over property keys are problematic when you're trying to use a static type system (TypeScript). They're possible, but problematic. Commented Nov 14, 2021 at 19:24
  • 1
    Side note: Please don't use the conditional operator where an if statement is the logical choice. There's literally no reason to do so. if (component === "x") { /*x = ...*/ } else { /*y = ...*/ }. Commented Nov 14, 2021 at 19:28
  • That was my first idea but I want to complicate things to learn how to use it. I came from use JavaScript so I wanna do things more complicated xD Commented Nov 14, 2021 at 19:39

2 Answers 2

2

@T.J. Crowder has commented some sound advice. However, if you are intent on using a loop in your method, you'll need to narrow the key type for the compiler:

TS Playground link

You can do it manually:

add (v: Vector): Vector {
  const vec = new Vector();

  for (const key in vec) {
    type K = 'x' | 'y';
    vec[key as K] = this[key as K] + v[key as K];
  }

  return vec;
}

Or by using an assertion function for the remainder of the scope:

function assertType <T = unknown>(value: unknown): asserts value is T {}
add (v: Vector): Vector {
  const vec = new Vector();

  for (const key in vec) {
    assertType<'x' | 'y'>(key);
    vec[key] = this[key] + v[key];
  }

  return vec;
}
Sign up to request clarification or add additional context in comments.

4 Comments

I'd also be curious to know OP's reason for not just doing new Vector(this.x + v.x, this.y + v.y)
There's no reason to repeat x and y, just use type K = keyof Vector;. (I'd also use Key or VectorKey for clarity, rather than K.)
@T.J.Crowder No, that still produces a compiler error: playground
@jsejcksn - Doh! Of course. (I've had my coffee now. :-) ) But I'd solve that by excluding function property keys rather than repeating x and y. Also, I'd strongly suggest not using empty assertion functions (in dev; they can be empty in prod after testing, e.g. via assert or similar). So something like this.
0

Personally this is the way I would do it.

  add(v: Vector): vector {
    const res = new Vector();

    Object.keys(this).forEach(component => {
      res[component] = this[component] + v[component];
    });

    return res;
  }

I threw together a quick sandbox example here

1 Comment

This produces a variation of the same compiler error in the question: TS Playground link

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.