Kuru
Kuru

Reputation: 1517

TypeScript write "if" in short

I have the code that sets a property only if the argument is truthy:

export class Vector {
    protected x: number = 0
    protected y: number = 0
    protected z: number = 0

    set(x?: number, y?: number, z?: number) {
        this.x = x ? x : this.x
        this.y = y ? y : this.y
        this.z = z ? z : this.z
    }
}

However, I don't want to provide a fallback value of the current value. Ideally, I want to just do nothing if the value is falsy, like this:

if (x) {
  this.x = x
}

if (x) {
  this.y = y
}

if (z) {
  this.z = z
}

… but I don't want to write it like this, it is not cool. I'm looking for something like this:

this.x = x ? x
this.y = y ? y
this.z = z ? z

Is there any similar syntax that does what I want?

Upvotes: 2

Views: 1103

Answers (3)

Parzh from Ukraine
Parzh from Ukraine

Reputation: 9855

Aside from other answers, you have three more options:

  • Use if one-liner:

    if (x) this.x = x
    if (y) this.y = y
    if (z) this.z = z
    
  • Use ?? operator (it wasn't available in 2018, when the question was asked):

    this.x = x ?? this.x
    this.y = y ?? this.y
    this.z = z ?? this.z
    
  • Use default values for optional parameters:

    export class Vector {
        protected x: number = 0
        protected y: number = 0
        protected z: number = 0
    
        set(x = this.x, y = this.y, z = this.z) {
            this.x = x
            this.y = y
            this.z = z
        }
    }
    

Upvotes: 0

Lars Holdaas
Lars Holdaas

Reputation: 750

Usually x && this.x=x would be the shortest syntax to get this done.

However x, y and z are all numbers. It's a bit dangerous to use this short-hand syntax for numbers. Consider the case where set is called with x=0. 0 && this.x=x would not execute this.x as 0 is falsey in Javascript. From reading your code this does not seem like what you want to achieve, instead you want to skip setting this.x in the case x is undefined.

In that case, I suggest the following code:

set(x?: number , y? : number , z? : number){
    typeof x === 'number' && (this.x = x);
    typeof y === 'number' && (this.y = y);
    typeof z === 'number' && (this.z = z);
}

That way your set-function will support sending 0 as an argument, which it currently does not.

Upvotes: 4

webNeat
webNeat

Reputation: 2828

A clean way to write your method is

set(x?: number , y? : number , z? : number){
  this.x = x || this.x;
  this.y = y || this.y;
  this.z = z || this.z;
}

An other way is

set(x?: number , y? : number , z? : number){
  x && this.x = x;
  y && this.y = y;
  z && this.z = z;
}

But, as @Lars Holdaas already mentioned, this will not support the falsy values (like 0 or ""). The generic way to solve this is by writing a validation or filter function to tell if the value is actually truly for that parameter or not.

// returns `true` if x is a number
const n = x => typeof n === 'number';

set(x?: number , y? : number , z? : number){
  n(x) && this.x = x;
  n(y) && this.y = y;
  n(z) && this.z = z;
}

Hope this helps :)

Upvotes: 2

Related Questions