# Use of base class to mutualize behavior / use of generic make the typing parametric

# First analysis
In the builders of Recipe & Ingredient entities from the [previous article](https://blog.carli.dev/builder-on-steroids-in-typescript-with-generics-and-proxy), we see that both classes  share some communalities :

- The private built entity `builtEntity`

- The constructor that initializes `builtEntity`

- The build method that returns the `builtEntity` once the building is done

One way to enhance the code would be to move the common behaviors of the 2 builders in a shared class.

# Refactoring

Let's first declare a protected property `builtEntity` in the class, that will hold the entity being built.

```typescript
export default class EntityBuilder<BuiltEntityType> {

  protected builtEntity: BuiltEntityType
}
```

The `< ... >` in the class definition denotes of the usage a type generic. This define a type or class that will use a parameter type, not yet known by the class or the type at the time of its definition.

As such the `builtEntity` property type will be of the one provided as type parameter of the `EntityBuilder` class

We can implement the `build` method, that will return the `builtEntity`.

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

> Note, once again that we use the `BuiltEntityType` parameter type, this time as the output of the `build` method.

To initialize the `builtEntity`  let's implement the constructor of the `EntityBuilder` class.

```typescript
constructor(TCreator: new () => BuiltEntityType) {
  this.creator = TCreator
  this.builtEntity = new this.creator()
}
```

As the types from `typescript`  are not present in the `js` runtime, the `constructor` need to have as input a generator of `BuiltEntityType` entities, that it can use to generate the new entities. To indicate that this generator should be generating `BuiltEntityType` we use the following `typescript` type syntax : `new () => BuiltEntityType`.  This generator passed as input will be, very conveniently, the `js`  class of the entity being built.

We just need to make  `Ingredient Builder`  &  `Recipe Builder` derives from the EntityBuilder class thanks to the `extends` keyword and we can get read of the  `constructor` and the `build` method in those classes.

This gives us : 

#### Entity builder

```typescript
export default class EntityBuilder<BuiltEntityType> {

  protected builtEntity: BuiltEntityType
  private creator: new () => BuiltEntityType

  constructor(TCreator: new () => BuiltEntityType) {
    this.creator = TCreator
    this.builtEntity = new this.creator()
  }
  public build(): BuiltEntityType {
    const returnedObj = this.builtEntity
    this.builtEntity = new this.creator()
    return returnedObj
  }
}
```

#### Ingredient builder

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

export default class IngredientBuilder extends EntityBuilder<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
  }
}
```

#### Recipe builder

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

export default class RecipeBuilder extends EntityBuilder<Recipe> {

  public static anIngredient() {
    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
  }
}
```

# Conclusion

Using `typescript` generics and the derivation of class we simplified our 2 builders.

It is good, but with this very few things are checked at built time, the `typescript` compiler ignoring some error or making some erroneous ones :

![Step 1 - Typescript errors.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647636555855/u5BBwgsvr.png)

In this sample, the `weightInGrams` property is defined, while `typescript` thinks is not. And name is `undefined` while `typescript` think it is. Also we will need to implement a builder for each entities.

Let's see how we can enhance things a bit in the next part.

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)



