What is the best way to implement this object builder in TypeScript strict mode without adding unnecessary weight to it?

After coming across a builder pattern online that I really liked, I found that it doesn't work in strict mode due to receiving the same error for the first 3 properties:

(property) PizzaBuilder.numberOfSlices: number
Property 'numberOfSlices' has no initializer and is not definitely assigned in the constructor.ts(2564)
export enum DoughType {
  HEALTHY,
}
export enum Topping {
  CHEESE,
}
export interface Pizza {
  numberOfSlices: number;
  isThin: boolean;
  doughType: DoughType;
  toppings: Topping[];
}

export class PizzaBuilder {
  private numberOfSlices: number;
  private isThin: boolean;
  private doughType: DoughType;
  private toppings: Topping[] = [];

  public setNumberOfSlices(numberOfSlices: number): PizzaBuilder {
    this.numberOfSlices = numberOfSlices;
    return this;
  }
  public setIsThin(isThin: boolean): PizzaBuilder {
    this.isThin = isThin;
    return this;
  }
  public setDoughType(doughType: DoughType): PizzaBuilder {
    this.doughType = doughType;
    return this;
  }
  public addTopping(topping: Topping): PizzaBuilder {
    this.toppings.push(topping);
    return this;
  }
  public build(): Pizza {
    if (this.isThin === undefined) this.isThin = false;
    if (this.numberOfSlices === undefined) this.numberOfSlices = 8;
    if (this.doughType === undefined) throw new Error('Dough type must be set');
    if (this.toppings.length < 1) this.toppings.push(Topping.CHEESE);

    return {
      numberOfSlices: this.numberOfSlices,
      isThin: this.isThin,
      toppings: this.toppings,
      doughType: this.doughType,
    };
  }
}

const pizza = new PizzaBuilder()
  .setIsThin(true)
  .setNumberOfSlices(6)
  .setDoughType(DoughType.HEALTHY)
  .addTopping(Topping.CHEESE)
  .build();

While I want to stay away from assigning default values to numberOfSlices, isThin, and doughType as it goes against the builder concept, setting them to undefined isn't a viable solution either.

Does anyone know of a solution that doesn't involve unnecessary complexity? Introducing extra booleans to track whether a property has been set seems like it would just add more clutter.

Answer №1

When working with TypeScript in strict mode, an error may occur because undefined cannot be assigned to types such as number, boolean, or DoughType. In strict mode, it is also required that each class property be initialized with a value of its corresponding type.

If the intention is for these properties to allow for the possibility of being undefined, they can be explicitly typed using a union type, which includes undefined as a valid value:

private numberOfSlices: number | undefined;
private isThin: boolean | undefined;
private doughType: DoughType | undefined;
private toppings: Topping[] = [];

For more information on Strict Class Initialization, you can refer to the TypeScript 2.7 release notes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The values of object keys are printed in a random order

Hey everyone, I have an object that looks like this var dates = { '2021-09-15': 11, '2021-09-16': 22, '2021-09-17': 38, '2021-09-18': 50, '2021-09-19': 65 }; I am trying to display the valu ...

Can you explain the distinction between the controls and get methods used with the FormGroup object?

I have encountered an interesting issue with 2 lines of code that essentially achieve the same outcome: this.data.affiliateLinkUrl = this.bookLinkForm.controls['affiliateLinkUrl'].value; this.data.affiliateLinkUrl = this.bookLinkForm.get(' ...

Field that only permits numerical input without triggering events for other characters

I've encountered some issues with the default behavior of the HTML number input and I'm looking to create a simple input that only allows numbers. To address this, I have developed a directive as shown below: import { Directive, ElementRef, Hos ...

The TypeScript function was anticipating one argument, however it received two instead

Can you help me fix the issue with my createUser() function? Why am I unable to pass parameters in Smoke.ts? Login.ts : interface User { url: string, email: string, } class Test{ async createUser(user: User) { await Page.setUrl(user.url); aw ...

An Angular module downloaded from npm seems to be lacking the required @NgModule declaration

There seems to be a missing @NgModule and @Directive declarations in an NPM module, even though they exist in the source code on Github. This is causing an issue with importing a directive for databinding from an HTML attribute. I am attempting to utilize ...

How can you create an interface where the value type is determined by the key, but not all keys are predefined?

Below is an illustration of a data structure that I aim to define as a type in TypeScript: const dataExample = { Folder: { "Filename.js": { lines: { total: 100, covered: 80, ...

Generate a type error if the string does not correspond to the key of the object

How can I trigger a type error in TypeScript 4.4.3 for the incorrect string 'c' below, which is not one of the keys of the object that is passed as the first parameter to the doSomething method? const doSomething = ({ a, b }: { a: number, b: stri ...

Tips on programmatically filtering angular lists

Is there a way to programmatically filter an Angular list? I'm currently working on a project where I need to filter subcategories by clicking on categories. For example, when clicking on "Drinks," I want to display items like Coke, Fanta, Pepsi... ...

Gathering adorned categorizations (sans any listed category divisions)

My current setup involves an event dispatcher class that triggers listeners on specified occurrences. I've successfully implemented registering event listeners via decorators, but I feel like there may be a better solution out there. At the moment, e ...

Adding ngrx action class to reducer registration

Looking to transition my ngrx actions from createAction to a class-based approach, but encountering an error in the declaration of the action within the associated reducer: export enum ActionTypes { LOAD_PRODUCTS_FROM_API = '[Products] Load Products ...

Combining Multiple TypeScript Declaration Files into an NPM Package for Seamless Importing with index.d.ts

I have a unique package structure that includes: myPackage/ |- types/ | |- type1.d.ts | |- type2.d.ts |- src/ | |- someUtilities.ts |- index.ts |- package.json |- tsconfig.json In my package, the index.ts file is handling imports and exports for all th ...

What is the method for defining a mandatory incoming property in an Angular2 component?

In my current project, I am developing a shared grid component using Angular2 that requires an id property. export class GridComponent { @Input() public id: string; } I'm looking for a way to make the id property mandatory. Can you help me with ...

I am not currently working on developing an angular application

Seeking assistance for the issue described below, as I have been struggling with it for three days. Any help would be greatly appreciated. Despite multiple attempts, the situation only seems to worsen with each try. The problem arises when attempting to ...

TypeScript: Unidentified reference to 'this' within the class

typescript version: 3.9.2 The goal is to define an interface constraint that permits only non-functional member keys on the class type NonFunctionKeys<T extends {}> = { [K in keyof T]-?: T[K] extends Function ? never : K }[keyof T]; class MyClas ...

How come the information I receive when I subscribe always seems to mysteriously disappear afterwards?

I've been working on a web project using Angular, and I've run into an issue with my code that's been causing problems for a while now. The problem lies in fetching data from a server that contains translations: getTranslations(): Observab ...

What is the use of the mongoose $gt operator in an Express application built with

I am searching for users whose tokens have not yet expired. try { const user = await User.findOne({ resetToken: passwordToken, resetTokenExpiration: { $gt: Date.now() }, _id: userId, }); if (!user) { throw new NotFoundEr ...

Limiting querySelector to a specific React component: a step-by-step guide

Is there a way to target a specific DOM element within a React component to change its color using the ComponentDidMount method? Parent component export class ListComponent extends Component<...> { render(): ReactNode { return ( ...

Dealing with Overwhelmingly Large Angular 5 Components

I'm currently developing a project in Angular 5 and one of our component files is becoming quite large, reaching nearly a thousand lines and continuing to grow. This will eventually make it difficult to manage and understand. We are seeking advice on ...

Using React with Typescript: Passing Props and Defining Data Types

As a relatively new TypeScript enthusiast, I find myself facing some challenges. Specifically, I am struggling with errors in my code and uncertain about how to properly pass props and select the correct type. Any guidance on this matter would be greatly a ...

Analyzing elements within an array using Angular 4

I have an array filled with various Objects such as: [ {"id":1,"host":"localhost","filesize":73,"fileage":"2018-01-26 09:26:40"}, {"id":2,"host":"localhost","filesize":21,"fileage":"2018-01-26 09:26:32"}, {...} ] These objects are displayed in the fol ...