Find Us and Follow Us

Typescript design patterns for SharePoint Framework Part 3 – Builder
TypeScript

Typescript design patterns for SharePoint Framework Part 3 – Builder

Content type Blog Post
Author Luis Valencia
Publication Date 18 Jan, 2026
Reading Time Less than 1 minute

Builder patte
builds a complex object using simple objects and using a step by step approach. This type of design patte
comes under creational patte
as this patte
provides one of the best ways to create an object.

A Builder class builds the final object step by step. This builder is independent of other objects.

For this patte
, we have taken an existing example https://www.tutorialspoint.com/designpatte
/builder
patte
.htm and translated it to Typescript. Data Access implementation details are left to the reader.

The idea on this example is to show how you can build a Complex object from single objects, a Meal from (burger, fries, soda). Suppose you have a Sharepoint List for Burgers, another list for Sodas, another one for desserts, and you want to build different Meals (Menus), so this would be a perfect sample.

UML

This is more or less the diagram of the classes were are coding below.

Diagram of coding

Diagram of coding

Project structure

We have created a component with all the needed class, lets discuss them one by one.

Components

Components

IItem.ts

This interface is the one that every item needs to implement to come with a common structure for all products.

import IPacking from "./IPacking";

interface IItem {  
    name(): string;
    packing(): IPacking;
    price(): number;
}

export default IItem;  

Ipacking.ts

This interface is the one that all packaging will use, eg: Bottle, Wrapper, etc, its the way to define common behavior and properties for each product packing.

interface IPacking {  
    pack(): string;
}

export default IPacking;  

Bottle.ts

This is one type of packing, it implements the IPacking interface.

import IPacking from "./IPacking";

class Bottle implements IPacking {  
    public pack(): string {
       retu
 "Bottle";
    }
}

export default Bottle;  

Wrapper.ts

import IPacking from "./IPacking";

class Wrapper implements IPacking {  
    public pack(): string {
       retu
 "Wrapper";
    }
}

export default Wrapper;  

Burger.ts

This is an abstract class from which all our specific burgers need to implement, its there to have a common structure for name, packing and pricing.

import IItem from "./IItem";  
import Wrapper from "./Wrapper";  
import IPacking from "./IPacking";

abstract class Burger implements IItem {  
    public name(): string {
        throw new Error("Method not implemented.");
    }

    public packing(): IPacking {
        retu
 new Wrapper();
    }

    public abstract price(): number ;

}

export default Burger;  

ChickenBurger.ts

import Burger from "./Burger";

class ChickenBurger extends Burger {  
    public price(): number {
        retu
 15;
    }

    public name(): string {
        retu
 "Chicken Burger";
    }
}

export default ChickenBurger;

VegBurger.ts

import Burger from "./Burger";

class VegBurger extends Burger {  
    public price(): number {
        retu
 11;
    }

    public name(): string {
        retu
 "Veg Burger";
    }
}

export default VegBurger;

Colddrink.ts

import IItem from "./IItem";  
import IPacking from "./IPacking";  
import Bottle from "./Bottle";

abstract class ColdDrink implements IItem {  
    public name(): string {
        throw new Error("Method not implemented.");
    }
    public packing(): IPacking {
        retu
 new Bottle();
    }

    public abstract price(): number ;

}

export default ColdDrink;

Coke.ts

import ColdDrink from "./ColdDrink";

class Coke extends ColdDrink {  
    public price(): number {
       retu
 2.5;
    }

    public name(): string {
        retu
 "Coca Cola";
    }
}

export default Coke;

Pepsi.ts

import ColdDrink from "./ColdDrink";

class Pepsi extends ColdDrink {  
    public price(): number {
       retu
 1.5;
    }

    public name(): string {
        retu
 "Pepsi Cola";
    }
}

export default Pepsi;

Meal.ts

This class will represent a full meal behavior, here we have the methods to add items to the Meal, get the cost and show the items belonging to the Meal.

import IItem from "./IItem";

class Meal {  
    private items: IItem[];

    public addItem(item: IItem): void {
        this.items.push(item);
    }

    public getCost(): number {
        let cost: number  = 0;
        for(let item of this.items) {
            cost+= item.price();
        }

        retu
 cost;
    }

    public showItems(): string {
        let retu
Str: string;
        for(let item of this.items) {
            retu
Str +="Item:" + item.name;
            retu
Str +=", Packing:" + item.packing().pack();
            retu
Str +=", Price: " + item.price();
        }
        retu
 retu
Str;
    }
}

export default Meal;  

MealBuilder.ts

Mealbuilder its just the class that uses the classes explained before to construct any type of meal, for sake of simplicity, we created only 2 meals here.

import Meal from "./Meal";  
import VegBurger from "./VegBurger";  
import Coke from "./Coke";  
import ChickenBurger from "./ChickenBurger";

class MealBuilder {  
    public prepareVegMeal(): Meal {
        let meal: Meal= new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        retu
 meal;
    }

    public prepareNonVegMeal(): Meal {
        let meal: Meal= new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Coke());
        retu
 meal;
    }
}

export default MealBuilder;  

ITypescriptDesignPatterns03BuilderProps.ts

We created a selectedMeal string property to take the decision on which meal to build.

export interface ITypescriptDesignPatte
s03BuilderProps {  
  description: string;
  selectedMeal: string;
}

TypescriptDesignPatterns03Builder.tsx

This is our component class, here we have a constructor and in the constructor we call the setMeal method, with the selected meal option as a parameter, and then we can define which meal to prepare. Once the meal is prepared, in the render method we can use the showItems method

import * as React from "react";  
import styles from "./TypescriptDesignPatte
s03Builder.module.scss";  
import { ITypescriptDesignPatte
s03BuilderProps } from "./ITypescriptDesignPatte
s03BuilderProps";  
import { escape } from "@microsoft/sp-lodash-subset";  
import MealBuilder from "./MealBuilder";  
import Meal from "./Meal";  
import { IPropertyPaneConfiguration } from "@microsoft/sp-webpart-base/lib/propertyPane/propertyPane/IPropertyPane";  
import {  
  PropertyPaneDropdown
} from "@microsoft/sp-webpart-base";
import Version from "@microsoft/sp-core-library/lib/Version";

export default class TypescriptDesignPatte
s03Builder extends React.Component<ITypescriptDesignPatte
s03BuilderProps, {}> {

  private mealBuilder: MealBuilder ;
  private items: string;
  private meal: Meal;

  constructor(props: ITypescriptDesignPatte
s03BuilderProps, state: any) {
    super(props);
    this.setMeal(props.selectedMeal);
    this.mealBuilder = new MealBuilder();
  }

  public render(): React.ReactElement<ITypescriptDesignPatte
s03BuilderProps> {
    retu
 (
        <div className={styles.typescriptDesignPatte
s03Builder}>
          <div className={styles.container}>
            <div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
              <div className="ms-Grid-col ms-lg10 ms-xl8 ms-xlPush2 ms-lgPush1">
                <span className="ms-font-xl ms-fontColor-white">Welcome to Burger Company!</span>
                <p className="ms-font-l ms-fontColor-white">You have selected the following.</p>
                  <span className={styles.label}>{this.meal.showItems()}</span>
              </div>
            </div>
          </div>
        </div>
      );
    }

  protected get dataVersion(): Version {
    retu
 Version.parse("1.0");
  }

  private setMeal(selectedMeal: string): void {
     if(selectedMeal === "VegMeal") {
        this.meal = this.mealBuilder.prepareVegMeal();
     }
     if(selectedMeal === "NonVegMeal") {
      this.meal = this.mealBuilder.prepareNonVegMeal();
   }
  }
}

And finally

TypescriptDesignPatterns03BuilderWebPart.ts

Here what we do is just to use our component and sending the parameter of the selected meal, which is just a normal dropdown with 2 hardcoded values.

import * as React from "react";  
import * as ReactDom from "react-dom";  
import { Version } from "@microsoft/sp-core-library";  
import {  
  BaseClientSideWebPart,
  IPropertyPaneConfiguration,
  PropertyPaneTextField,
  PropertyPaneDropdown
} from "@microsoft/sp-webpart-base";

import * as strings from "TypescriptDesignPatte
s03BuilderWebPartStrings";  
import TypescriptDesignPatte
s03Builder from "./components/TypescriptDesignPatte
s03Builder";  
import { ITypescriptDesignPatte
s03BuilderProps } from "./components/ITypescriptDesignPatte
s03BuilderProps";  
import { ITypescriptDesignPatte
s03BuilderWebPartProps } from "./ITypescriptDesignPatte
s03BuilderWebPartProps";

export default class TypescriptDesignPatte
s03BuilderWebPart extends  
  BaseClientSideWebPart<ITypescriptDesignPatte
s03BuilderWebPartProps> {

  public render(): void {
    const element: React.ReactElement<ITypescriptDesignPatte
s03BuilderProps > = React.createElement(
      TypescriptDesignPatte
s03Builder,
      {
        description: this.properties.description,
        selectedMeal: this.properties.selectedMeal
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected get dataVersion(): Version {
    retu
 Version.parse("1.0");
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration  {
    retu
 {
      pages: [
        {
          header: {
            description: "Header"
          },
          groups: [
            {
              groupName: "Group",
              groupFields: [
                PropertyPaneDropdown("meal", {
                  label: "Select meal",
                  options: [
                    { key: "Veg", text: "Veg" },
                    { key: "Nonveg", text: "Nonveg" }
                  ],
                  selectedKey: "Nonveg"
                })
              ]
            }
          ]
        }
      ]
    };
  }
}

Data source implementation is left to the reader.
This project is in my github repo: https://github.com/levalencia/TypescriptDesignPatte
s03-Builder

About the Author: 

Luis Valencia, CTO at Software Estrategico, Medellin, Colombia, independent blogger and still a coder, after 17 years of experience in the field and regardless of my position, and mostly with SharePoint/Office Products, I still love to code, open Visual Studio and bring solutions to users and to the community its what makes me wake up every mo
ing.

Feel free to contact me via twitter direct messages, @levalencia

Reference: 

Valencia, L (2018). Typescript design patte
s for SharePoint Framework Part 3 – Builder. Available at: http://www.luisevalencia.com/2018/03/19/typescript-design-patte
s-for-sharepoint-framework-part-3-builder/
 [Accessed 12 November 2018]

Tags

Builder Design patterns SharePoint Framework TypeScript

trending posts

View all ESPC
Learning Hub Content

view all