October 26, 2018

Type System in JavaScript: What It Is and Why It Matters

by Camilo Reyes

Type System in JavaScript

JavaScript is characterized as a dynamic and weakly typed programming language. The ability to manipulate DOM elements in a dynamic way is empowering to the developer. At the onset, it seems like dynamic typing frees the developer from extraneous code. To some, adding a stricter type system becomes an impediment to developers’ productivity.

In the early web, JavaScript was scarce. The demand for rich user interaction didn’t make sense for static web pages. JavaScript’s footprint was often dwarfed by CSS and images. In more recent years, this demand for rich client-side interfaces has exponentiated. It is safe to assume JavaScript is the programming language of the web.

But, as code bases grow, and more contributors add to its complexity, can a type system start to make sense? As bugs and complexity increases, code quality becomes the focus on how fast a team can deliver.

What Is A Type System?

In JavaScript, a type system adds type safety checks to a program. This can happen at compile time or during the execution of the code. Given the dynamic nature of JavaScript, you can assign a string to a variable then use this same variable like a number. A type system will flag these programming mishaps and let you know of a possible error.

A type system can look like a data contract. The programmer specifies what a variable is for. This enables code readers to know what the original author intends. Imagine a type system as a formal contract and an effective way to communicate program specs.

A type system is much like a mini unit test. The type checking system lets the programmer know whether the test passes or fails. This frees the original author from having to specify type intent in an actual unit test.

You can use a type system to automate type safety checks. This becomes your first line of defense towards thwarting bugs in the code.

Why Does It Matter?

Dynamic or duck typing is great for prototypes and quick proof of concepts. Prototype code increases the productivity of a single developer. When a prototype comes from a small team, the velocity is high, because communication is much easier. Once this makes it to production, however, it can grow into a maintenance nightmare. There is a point where bugs can bring any software project down to a crawl.

There is value in defining a specific type to a variable and having a system that validates types. Any programmer unfamiliar with the program can read and understand type definitions. The type system is the data contract to communicate program specifications to newcomers. As more contributors add to the program, data types form a way to validate assumptions.

Type systems build the architecture necessary to communicate intent and clean design. Beauty is in code built around strict data models that meet business requirements.

Think of a type system as a safety net and a communication tool. Having explicit types with validation adds accountability to a team of programmers. When type checking is part of the build, it shields the code base from many bugs.

Empirical evidence suggests a 15% bug reduction by adding a type system. So, when facing a large enterprise-grade JavaScript project, it is a good idea have one — as it is an effective way to increase code quality and deliver faster.

Type Safety Checks

Time for the code. Let’s demonstrate a type system using React PropTypes without React. To illustrate the issue, I’ll fabricate a bug that can happen to anyone. Say we have a component for adding two numbers. Due to changes to the team, the original intent of the component gets forgotten. Dynamic typing can build tribal knowledge around data contracts which turn into a myth.

For example:

const props = {  
  x: 1,
  y: '1'
};

function addNumbersComponent(props) {  
  return props.x + props.y;
}

addNumbersComponent(props);  

JavaScript allows this behavior and even gives you a return value too. It may not be what you expect but it does work without throwing any errors. There is permissiveness here that should make programmers pine for basic type checking.

To quell this behavior, one can do:

const propTypes = {  
  x: PropTypes.number,
  y: PropTypes.number
};

PropTypes.checkPropTypes(propTypes, props, 'props', 'addNumbersComponent');  

PropTypes build a line of defense against type mishaps and gives you feedback. Having basic type checking warns you when there is a programmatic error. One idea is to fail the build when these warnings crop up in your JavaScript code.

This is the message you see when there is a warning with a type:

PropTypes Warning

There is value in this feedback because it automates type checking. In programming, the job is often to automate as much as possible and this includes type checking. The feedback loop can be shorter when type checking is part of the build. Note that this warning does not show up in a production build. Consider adding type checking as part of the unit tests to fail the build.

Feel free to play around with the sample code, it is out on CodePen.

Conclusion

A type system can be your first line of defense against bugs in production. Dynamic typing is good for prototypes with small teams but can fall short in enterprise-grade software. Large projects with poor coding architecture are at risk when documentation is lacking. A type system reduces risk, is a communication tool, and enhances the architecture.

As JavaScript code bases grow both in size and complexity, there is value in type checking. A good type system builds on top of JavaScript native types and does basic type checking.

Consider adding type checking as part of a build to shorten the feedback loop. The less time it takes to get feedback, the faster you can thwart bugs.