The last days of my type checker for JavaScript

TL;DR Last year, I started to work on the 2.0 version of my static type checker for JavaScript written in Rust, but, unfortunately, I see that nowadays, TypeScript won. The idea of strict type-checking for JavaScript is less popular than in 2019. Additionally, another way to bring stricter types into the web exists. So, I lost my belief that there could be an audience for such a tool and decided to close the project.

To make the story short

At the beginning of 2019, I worked in a small outsourcing company called WookieeLabs. In most of the projects, we preferred to use Flow over the TypeScript. There were a lot of benefits such as nominal classes, type variances, opaque types, smooth integration with React. But the main reason was that Flow in 2019 was just JavaScript with types.

But the way Flow type inference was working in 2019 was not ideal:

const id = x => x;
const a = id(2); // number | string
const b = id("string"); // number | string

You can play with this example here

So, Flow analyzed the usage of the function and, based on it, inferred the type of a function. In the example above, we provided to the id function a number and a string, so, based on the usage, the tool infered the type of the id as (x: number | string) => number | string.

However, the Flow team did a significant job of fixing such behavior by requiring annotations in places where the tool knows it will not have a local typing context. You can read about it here.

At the same time, there was hype about the new “language” (syntax for OCaml) called ReasonML (today there is also an alternative project called ReScript).

And I was wondering, what if we take the power of the Hindley-Milner type inference, as strict as possible type system for JavaScript and the simple Flow like types syntax and combine it inside a single tool. So, I created Hegel as my university bachelor project and started to talk about it at some conferences.

You can check the main differences in comparison with TypeScript here and with Flow here

But my favorite example that describes what the tool provides is this:

// The type of the function is: (string) => { name: string, ... } throws SyntaxError | TypeError
function deserializeUser(stringifiedUserJson) {
  /* the result type is unknown because there is no `any` type */
  const maybeUser  = JSON.parse(stringifiedUserJson); /* it throws a SyntaxError, so it was added to the type signature */
  if (
    typeof maybeUser === "object" && maybeUser !== null       // a proof that `maybeUser` is an object
    "name" in maybeUser && typeof maybeUser.name === "string" // a proof that there is a property called `name` with `string` type
  ) {
    return maybeUser; // the result type is { name: string, ... }
  }
  throw new TypeError("Provided serialized user is invalid!");
}

try {
  /* the type of `foo` is { name: string, ... } */
  const foo = deserializeUser("42");
} catch (e) {
  // the type of `e` is SyntaxError | TypeError | unknown
}

And there were difficulties

Because most of the time I was the only contributor in the core modules, working on a full-time job and continuing study as a master didn’t give me enough time to contribute more, so there were (and still) a lot of issues and bugs, that should be fixed, so the development took a long time.

Also, speaking at local conferences didn’t help a lot in finding a lot of new contributors.

I want to thank everyone who supported me with the project, proposed exciting ideas, and helped me prepare different examples. Some people also helped me fix grammar mistakes in the documentation, review all the sections, and set up the CI/CD. You all are unbelievable.

At some point (around March 2021), I struggled with all the COVID-19 restrictions and the rumors about the upcoming war between Ukraine and Russia. So, my wife and I relocated to the Netherlands two months before the war started.

I also want to say a big thank you to JetBrains. You not only gave me the possibility to work on such exciting projects but literally saved my and my wife’s lives.

After a while, I started to rework the core system differently to support an incremental compilation (to improve analysis speed) and an intermediate representation (to support multiple syntaxes, including TypeScript syntax; the tool had previously worked directly with the AST).

But during that time, I felt like I was trying to overtake a Ferrari, and the community interest in such a project was already insignificant.

Reflection on the project

For today, I have only results for the State of JavaScript 2022, and as soon as the results of State of JavaScript 2023 become available, I will update the numbers.

The following things made me lose the belief that I should continue my work:

  • The developers of TypeScript are doing an excellent language and working a lot on its improvement, so it is the most popular alternative for JavaScript nowadays (98.9% question respondents use TypeScript, the nearest competitor is Elm with the result 2.3%)
  • JavaScript as a technology and community is already mature, so the new tools, frameworks, and libraries take a small part of the market. Here you can take a look on the usage of Deno (one of the Deno prototypes was presented in 2019) comparing to the Node.js, or the comparison of frameworks usage where we can see that the new frameworks such as Solid.js or qwik take 6% and 2%
  • Based on my communication with different developers, I realized that TypeScript changed how developers think about the types in JavaScript. In 2019, people thought of types as the rules restricting the language for developing safer software (fewer bugs or unexpected runtime errors). Still, today, people think more about describing any (even not so secure) software with types. All of these fancy template literal types, conditional types, an unchecked body of assert functions and type predicates, and of course any, give people a fantastic tool to cover existed code with types but doesn’t force to re-design it to make it safer.
  • I see other opportunities to increase the language diversity on the web (further in the article)

So, primarily based on those things, I decided to close the project Hegel.

Other projects and other opportunities

Last year, I unexpectedly realized what a big and fantastic job was done on wasm as a technology. Proposals such as GC proposal and Exception handling help to bring to the web more and more programming languages with stricter type system that are already familiar to people, that have already a mature ecosystem of build tools, libraries, frameworks, but also Component Model proposes the solution to interop between of them, that means sharing parts of the extensive ecosystems between each other.

So, this is one of the reasons why I decided to join Kotlin/Wasm team and focus most of the time on helping to bring the amazing Kotlin and its ecosystem into the web.

Suppose you are still looking for the analyzing tool for your JavaScript project. In that case, you can bring your attention to a cool project called Ezno, which provides strict type checking and also (because it’s a full compiler) focuses on optimizing your code. Ben is doing an incredible job.

Share: Twitter LinkedIn