Skip to content

Simplifying JavaScript Dictionary Creation with reduce in TypeScript

Updated: at 02:12 PM

Simplifying JavaScript Dictionary Creation with reduce in TypeScript

When working with JavaScript or TypeScript, developers often find themselves manipulating collections such as arrays, sets, and dictionaries. The process of converting an array to a dictionary, for example, can be accomplished in several ways. This blog post explores the benefits of using the reduce method over the commonly used forEach. Specifically, we will examine how this switch can positively affect the Cyclomatic Complexity of your codebase, a key metric in understanding code maintainability and quality.

Initial Approach Using forEach

Firstly, let’s consider a TypeScript example featuring the interface SessionInterest and an array named sessionInterestTotals with objects conforming to this interface.

interface SessionInterest {
  sessionId: number;
  InterestLevel2Count: number;
  InterestLevel3Count: number;
};

const sessionInterestTotals: SessionInterest[] = [
  { sessionId: 1, InterestLevel2Count: 10, InterestLevel3Count: 5 },
  { sessionId: 2, InterestLevel2Count: 20, InterestLevel3Count: 7 },
  // ... more data
];

The task at hand is to transform this array into a dictionary, where the sessionId serves as the key. Using forEach, the transformation looks as follows:

const sessionInterestTotalDict: Record<number, SessionInterest> = {};

sessionInterestTotals.forEach((entry: SessionInterest) => {
  sessionInterestTotalDict[entry.sessionId] = entry;
});

Cyclomatic Complexity of forEach Approach

The Cyclomatic Complexity of this code is relatively low but not minimal. The forEach loop adds an additional level of complexity due to the function it takes as an argument. For this particular example, it would likely be a Cyclomatic Complexity of 2, considering the loop and the arrow function.

Refactor with reduce

reduce is a powerful array method in JavaScript and TypeScript that can condense an array into a single value, such as an object or a number. Here’s how one could refactor the code using reduce:

const sessionInterestTotalDict: Record<number, SessionInterest> = sessionInterestTotals.reduce((acc: Record<number, SessionInterest>, entry: SessionInterest) => {
  acc[entry.sessionId] = entry;
  return acc;
}, {});

Cyclomatic Complexity of reduce Approach

One of the advantages of using reduce is that it typically results in lower Cyclomatic Complexity. In this specific example, the complexity would be 1 since there’s only a single function to consider—the one passed to reduce. This is a straightforward, albeit minor, reduction in complexity compared to the forEach approach.

Deeper Dive into Cyclomatic Complexity

Cyclomatic Complexity is a software metric used to indicate the complexity of a program. It is computed using the control flow graph of the program. A program with high Cyclomatic Complexity has more branches and is, therefore, more complex and potentially harder to understand and test. Lowering the complexity often results in code that is easier to manage and debug.

TypeScript Constructs Involved

Interface and Record

We used TypeScript’s interface to define the shape of objects, and Record as a utility type to specify the dictionary’s key-value pair types. These features not only enhance type safety but also self-document the code, reducing the need for external comments.

Conclusion

While forEach might appear to be a straightforward approach for converting arrays to dictionaries, reduce is a powerful alternative that often results in simpler and cleaner code with reduced Cyclomatic Complexity. The method is aligned with best coding practices, offering a functional approach that can be easier to reason about. Understanding these nuances can equip developers to make informed decisions, thereby writing code that is not only robust but also maintainable.

Check out the ORM (Object Relational Mapper) PRISMA. The database access method I use in all my projects