Jalpster
Jalpster

Reputation: 39

Specify what optional property to set in Typescript class constructor

I have a class that looks as follows:

export class Lifter {
id: string;
name: string;
weightclass: number;
bestSnatch: number;
bestCJ: number;
bestTotal: number;
bio: string;
imageURL: string;


constructor(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, bio="Default biography text", imageURL = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Arh-avatar.jpg") {
    this.id = id;
    this.name = name;
    this.weightclass = weightclass;
    this.bestSnatch = bestSnatch;
    this.bestCJ = bestCJ;
    this.bestTotal = bestTotal;
    this.bio = bio;
    this.imageURL = imageURL;
    
}

}

So in the constructor I pass default values for the properties "bio" and "imageURL". This is working fine when I create a new Lifter by:

new Lifter("1","Jesper",73,107,125,220),

the default values for Bio and ImageURL are successfully being added. Now to my question.

Is it possible to enter a value for the imageURL-property without passing a value to the bio-property?

I would in some cases want to add just an ImageURL, sometimes just a bio, sometimes both of them and sometimes none of them. I hope the question and the problem is somewhat clear.

The different calls I would want to be functioning is as follows:

new Lifter("1","Jesper",73,107,125,220), //None of the properties
new Lifter("2","Alfred",83,187,205,220,"Some Biography"), //Biography passed
new Lifter("3","Manfred",73,107,125,220,"https://www.w3schools.com/howto/img_avatar2.png"),//ImageURL passed
new Lifter("4","Sigfred",73,107,125,220,"Some other biography" ,"https://www.w3schools.com/howto/img_avatar2.png"),//Values for both properties passed

For clarification, it's just the 3rd case above that I have a problem with.

Upvotes: 1

Views: 254

Answers (3)

Pawel Woroniecki
Pawel Woroniecki

Reputation: 519

Besides already described ways there are two other ways I just wanted to mention:

  1. Static factory methods:
export class Lifter {
  id: string;
  name: string;
  weightclass: number;
  bestSnatch: number;
  bestCJ: number;
  bestTotal: number;
  bio: string = "Default biography text";
  imageURL: string = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Arh-avatar.jpg";

  private constructor(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number) {
    this.id = id;
    this.name = name;
    this.weightclass = weightclass;
    this.bestSnatch = bestSnatch;
    this.bestCJ = bestCJ;
    this.bestTotal = bestTotal;
  }

  static create(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, bio: string, imageURL: string): Lifter {
    return new Lifter(id, name, weightclass, bestSnatch, bestCJ, bestTotal);
  }

  static createWithDefaultBioAndImageURL(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number): Lifter {
    return new Lifter(id, name, weightclass, bestSnatch, bestCJ, bestTotal);
  }

  static createWithDefaultBio(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, imageURL: string): Lifter {
    const lifter = new Lifter(id, name, weightclass, bestSnatch, bestCJ, bestTotal);
    lifter.imageURL = imageURL;
    return lifter;
  }

  static createWithDefaultImageURL(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, bio: string): Lifter {
    const lifter = new Lifter(id, name, weightclass, bestSnatch, bestCJ, bestTotal);
    lifter.bio = bio;
    return lifter;
  }
}

const lifter1 = Lifter.create("3","Manfred",73,107,125,220,"sampleBio", "https://www.w3schools.com/howto/img_avatar2.png");
const lifter2 = Lifter.createWithDefaultBio("3","Manfred",73,107,125,220,"https://www.w3schools.com/howto/img_avatar2.png");
const lifter3 = Lifter.createWithDefaultImageURL("3","Manfred",73,107,125,220,"sampleBio");
const lifter4 = Lifter.createWithDefaultBioAndImageURL("3","Manfred",73,107,125,220);

Example here

  1. Builder pattern

It can be implemented in several different ways, below is just sample one but you can also modify it in some ways, e.g. Lifter class could accept only LifterBuilder in constructor as a parameter and grab parameters from it - this way you could prevent initialization of this class without builder. The exact implementation depends on your needs and preferences.

export class Lifter {
  id: string;
  name: string;
  weightclass: number;
  bestSnatch: number;
  bestCJ: number;
  bestTotal: number;
  bio: string = "Default biography text";
  imageURL: string = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Arh-avatar.jpg";

  constructor(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, bio: string, imageURL: string) {
    this.id = id;
    this.name = name;
    this.weightclass = weightclass;
    this.bestSnatch = bestSnatch;
    this.bestCJ = bestCJ;
    this.bestTotal = bestTotal;
  }
}

export class LifterBuilder {
  id: string;
  name: string;
  weightclass: number;
  bestSnatch: number;
  bestCJ: number;
  bestTotal: number;
  bio: string = "Default biography text";
  imageURL: string = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Arh-avatar.jpg";

  constructor(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number) {
    this.id = id;
    this.name = name;
    this.weightclass = weightclass;
    this.bestSnatch = bestSnatch;
    this.bestCJ = bestCJ;
    this.bestTotal = bestTotal;
  }

  withBio(bio: string): LifterBuilder {
      this.bio = bio;
      return this;
  }

  withImageURL(imageURL: string): LifterBuilder {
      this.imageURL = imageURL;
      return this;
  }

  build(): Lifter {
      return new Lifter(this.id, this.name, this.weightclass, this.bestSnatch, this.bestCJ, this.bestTotal, this.bio, this.imageURL);
  }
}

const lifter = new LifterBuilder(...).withBio(...).withImageURL(...).build(); // just call withBio or withImageURL when you need them and don't call any of them if you don't want to change default values

Upvotes: 0

thabs
thabs

Reputation: 613

One way of doing this is through the object destructuring workaround for named parameters.

Your constructor destructures the object passed in as an argument:

constructor(id: string, name: string, weightclass:number, bestSnatch:number, bestCJ:number, bestTotal:number, {bio="Default bio", imageURL = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Arh-avatar.jpg"} = {}) {
  this.id = id;
  this.name = name;
  this.weightclass = weightclass;
  this.bestSnatch = bestSnatch;
  this.bestCJ = bestCJ;
  this.bestTotal = bestTotal;
  this.bio = bio;
  this.imageURL = imageURL;
}

And you can call it like this by passing in appropriate objects:

new Lifter("1","Jesper",73,107,125,220)
new Lifter("2","Alfred",83,187,205,220,{bio: "Some Biography"})
new Lifter("3","Manfred",73,107,125,220,{imageURL: "https://www.w3schools.com/howto/img_avatar2.png"})
new Lifter("4","Sigfred",73,107,125,220,{bio: "Some other biography" , imageURL: "https://www.w3schools.com/howto/img_avatar2.png"})

Upvotes: 1

Meqwz
Meqwz

Reputation: 1491

You could pass a null in for bio, or you could make it optional as stated above. bio has to have a value when you create a new instance of the class because that's the way that you've defined the class.

new Lifter("3","Manfred",73,107,125,220,null,"https://www.w3schools.com/howto/img_avatar2.png"),//ImageURL passed

Upvotes: 0

Related Questions