Type Safety:
Introduction
Type Safety for JavaScript
When you create a new project with create-composi-app
it comes set up to provide you with the ability to have type safe JavaScript. It does this by telling Visual Studio Code to use its TypeScript Language Service to type check you JavaScript in real time, as you write it.
JavaScript is Loosely Typed
JavaScript is not strongly typed. It was designed to run in the browser, so it has no need to be built or compiled. Unlike every other language out there, JavaScript is the only language that has to deal with the browser's DOM. The DOM has its own type system and JavaScript has to deal with that. To do so, JavaScript uses type coercion. For example, if you use document.getElementById
you get an object of type Element
. But document.querySelector
returns HTMLElement
. These are not the same thing. If the element you were getting was an input, its type would be HTMLInputElement
, which is different from the previous two types. In a strongly typed language these would not be interchangeable because their properties do not overlap. Through type coercion JavaScript lets you use access the DOM without having to thing about the underlying types.
Suppose you use getElementById
to get an input element. Then you want to get the value of that input like this:
const formInput = document.getElementById('form-input')
const value = formInput.value
This seems straightforward. It's something we do all the time. But what's really happening is the query is returning a type Element
. This is a very generic type. It has no value property. So when we try to access the value property on formInput
JavaScript sees that you're trying to access the value property and coerces formInput
to type HTMLInputElement
.
Type coercion makes it easy to work with the DOM. However the when and how type coercion happens is not always clear to developers, resulting in unexpected results. On top of that, because JavaScript is an interpreted language that runs in the browser, there is no way to know if code is correct until it loads in the browser. Basically the browser is your compiler and test environment. Strongly typed languages require a build step where the code is quecked for type correctness. If it is not correct, the build fails with relavant information about the type errors so you can address them.
For simple JavaScript, running it in the browser to catch errors is not a big deal. But if the code base is large and complex, this becomes couterproductive. The number and types of errors in a code base increase exponentially with the number of people working on it.
Prevention is the Best Cure
There are several trends to avoid the many types of JavaScript errors that can cause a crash. Linting with JSHint, ESLint, etc., warns you about dubious patterns and usages in your code. Prettier makes the code formatting consistent between team members. And there are now dozens of typed languages that compile to JavaScript. These provide static type safety at build time. This verifies that the types are correct before the JavaScript loads i the browser. There are many languages that provide static type checking for JavaScript: GWT, ClosureScript, Elm, PureScript, Reason, TypeScript, etc.
Regardless of what language you use to provide type safety for your code, once it is converted to JavaScript and run in the browser or in Node, there is no type safety. If all the code is from you or your team, you can have a high degree of certainty that your code will be type safe. However, if you are using third party libraries, data or APIs you cannot be sure. In such a case the only way to be sure that your code is type safe during runtime is to use type guards.
JSDoc
Composi provides type safety through a different approach. It uses TypeScript for type safety, but directly on JavaScript. TypeScript was designed to be able to understand JavaScript type usage through inference. This is nice, but not that useful because in most cases it treats so many things as type any
. TypeScript understands JSDoc comments, including the type information that closely corresponds to those of TypeScript. This means you can provide your JavaScript code with type information with JSDoc comments that TypeScript can understand, allowing it to verify the correctness of types. This means as you type JavaScript you will get both warning about incorrect type usage and rich Intellisense about the code you are using and code completion with hints.
All the default Composi code already comes typed for you. But any code you write will need type definitions to make it type safe. You can learn how to provide JSDoc type definition in the docs for typing.