# Builder pattern on steroïds with generics and proxy in Typescript


# Context

Using an hexagonal or clean architecture is a good way to have a back-end centerred on the business value provided by the application it serves while making it robust on technological changes & evolutions

The business entities are at the core of this architecture. Those entities reflect the different concepts that are manipulated by the back-end of the application. As such another common good practice is to have builders classes to create those entities. As their name indicates, those builder classes follow the [Builder Design Pattern](https://refactoring.guru/design-patterns/builder).

When you application grows, the number of  your business entities can grows quite quickly. As such having a common infrastructure for all those builders of business entities make the creation process less cumbersome.

> Using `typescript` and the power of generics, we will see how one can create a base class providing a lot of type checking feature **at build time** and runtime compatibility that removes the needs of code duplication.

The main goal of this group articles is to showcase some of the latest typescript feature will providing a useful  helper that you can use in your projets.


# Use case

Imagine I want to create an App for storing cooking recipes. I will start simple with at 2 business entities : one that represents a recipe and another one that represents an ingredient of the recipe.
A ingredient will have some properties such as its `kind`, its amount in `weight` and a `name`. 
A recipe will have some properties too : a difficulty, a list of ingredients and a name.

I will need also builders for those two entities in order to conveniently build each one of those entities.

In typescript, this translate into code with :

##### Ingredient Business Entity

```typescript
export default class IngredientBE {
  public kind: EKind
  public weightInKg?: string
  public name: string
}

export enum EKind {
  Liquid = 0,
  Vegetable = 1,
  Fruit = 2,
  Meat = 3,
  Condiment = 4,
  Other = 5,
}
```

#### Recipe Business Entity

```typescript
export default class Recipe {
  public ingredients: Ingredient[]
  public difficulty: EDifficulty
  public name: string
}

export enum EDifficulty{
  Easy = 0,
  Medium = 1,
  Hard = 2
}  
```

#### Ingredient builder

```typescript
import Ingredient, { EKind } from 'src/useCases/business/entities/Ingredient'

export default class IngredientBuilder {

  private builtEntity: Ingredient

  constructor() {
    this.builtEntity = new Ingredient()
  }

  public static anIngredient() {
    return new IngredientBuilder(Ingredient)
  }
  public withWeightInGrams(weightInGrams?: number) {
    this.builtEntity.weightInGrams =  weightInGrams
    return this
  }

  public withKind(kind: EKind) {
    this.builtEntity.kind = kind
    return this
  }
  public withName(name: string) {
    this.builtEntity.name = name
    return this
  }

  public build(): Ingredient {
    const returnedObj = this.builtEntity
    this.builtEntity = new Ingredient()
    return returnedObj
  }
}
```

#### Recipe builder

```typescript
import Ingredient from 'src/useCases/business/entities/Ingredient'
import Recipe, { EDifficulty } from 'src/useCases/business/entities/Recipe'

export default class RecipeBuilder {

  private builtEntity: Recipe

  constructor() {
    this.builtEntity = new Recipe()
  }

  public static anRecipe() {
    return new RecipeBuilder(Recipe)
  }
  public withDifficulty(difficulty: EDifficulty) {
    this.builtEntity.difficulty = difficulty
    return this
  }

  public withName(name: string) {
    this.builtEntity.name = name
    return this
  }

  public withIngredients(ingredients: Ingredient[]) {
    this.builtEntity.ingredients = ingredients
    return this
  }

  public build(): Recipe {
    const returnedObj = this.builtEntity
    this.builtEntity = new Recipe()
    return returnedObj
  }
}
```

# Up next

From this simple data models as a starting point, I will take a very didactic approach to explain the different feature of `typescript` we can use to dramatically simplify this code.

If you are already familiar with advanced typescript features and just want to see what could be a convenient-to-use builder infrastructure that makes good use of those features, please have a look at this repo : [berlingo-ts](https://gitlab.com/ArthurCrl/berlingo-ts)

