DEV Community

Cover image for Understanding the Open-Closed Principle in TypeScript and React
Akbar Julian Khatibi
Akbar Julian Khatibi

Posted on • Updated on

Understanding the Open-Closed Principle in TypeScript and React

The Open-Closed Principle (OCP) is one of the five principles of SOLID that guides developers in creating maintainable and scalable code. According to the principle, software entities such as classes, modules, and functions should be open for extension but closed for modification. This principle minimizes the risk of introducing bugs or breaking existing functionality when adding new features. Although SOLID was formulated for object-oriented languages, its principles, including OCP, can be applied to other paradigms such as TypeScript and React.

In TypeScript, the Open-Closed Principle can be achieved using interfaces and class inheritance. An interface defines a set of rules that classes can implement, allowing them to be open for extension. The classes can be used interchangeably in the program, keeping the other parts of the program closed for modification.

For instance, let's consider a geometry program that calculates the area of different shapes. In the example below, the getArea function needs modification to support new shapes, which violates the Open-Closed Principle:

function getArea(shape: { kind: string, length: number }) {
 if (shape.kind === 'square') {
 return shape.length * shape.length;
 }
}
Enter fullscreen mode Exit fullscreen mode

A better approach would be to create a Shape interface that each shape can implement:

interface Shape {
 area: () => number;
}

class Square implements Shape {
 constructor(public length: number) {}
 area() {
 return this.length ** 2;
 }
}
Enter fullscreen mode Exit fullscreen mode

With this approach, each shape defines its area method, and the getArea function is not required. New shapes can be added without modifying existing code, adhering to the Open-Closed Principle.

A Note About Typescript

Even though TypeScript is primarily for type checking and doesn't directly impact the runtime behavior of the code, it can still catch potential bugs at compile time rather than at runtime.

Moreover, interfaces can guide the design of your code by specifying contracts that classes must adhere to. In this case, the Shape interface is saying that any shape must have an area method that returns a number. This encourages a consistent design where different shape classes can be treated in a uniform way.

So, while TypeScript interfaces don't have a direct impact on the resulting JavaScript code, they have a significant impact on the TypeScript code's correctness, maintainability, and design.

Examples In React
In React, the Open-Closed Principle can be applied by creating components that accept props and children. This way, the components can be extended by passing different props and children without modifying the component's code.

For example, a List component can accept an array of items and a function to render each item (renderItem), making the component highly reusable and extendable:

function List({ items, renderItem }) {
 return (
 <ul>
 {items.map(renderItem)}
 </ul>
 );
}
Enter fullscreen mode Exit fullscreen mode

With this component, we can create a list of strings, a list of numbers, a list of complex objects, etc., by passing a different renderItem function and items array. We can extend the List component's functionality without modifying its code, keeping with the Open-Closed Principle.

Remember, adhering to the Open-Closed Principle can help you create robust and maintainable code in TypeScript and React. Happy coding!

Top comments (0)