First look: adding type annotations to JavaScript

[2022-03-09] dev, javascript, es proposal
(Ad, please don’t block)
  • Update 2022-03-10: I’m quoting a few insightful tweets at the end of this blog post.

The ECMAScript proposal “Types as comments” (by Gil Tayar, Daniel Rosenwasser, Romulo Cintra, Rob Palmer, and others) is about adding type annotations to JavaScript (there is also an accompanying blog post).

Such type annotations would look similar to TypeScript’s and Flow’s annotations and are completely ignored at runtime.

In this blog post, I briefly explain how the proposed type annotations would work and then describe what I think about them.

How do the proposed type annotations work?  

This is an example:

function add(x: number, y: number) {
  return x + y;
}

The parameters x and y have type annotations: The type number, separated by a colon.

This is how these annotations are handled:

  • At runtime, JavaScript engines completely ignore them – as if they were comments.

  • At development time, type checkers can statically analyze the annotations and warn developers about potential issues.

So far, we have only seen relatively simple type annotations. More complicated ones are also proposed – e.g.:

  • Interfaces (interface)
  • Type aliases (type)
  • Type assertions (as)
  • Generic invocations (e.g. add<number>(4, 5))
  • And more (see proposal)

Thoughts on adding type annotations to JavaScript  

My thoughts  

Upsides:

  • Having a standard for type notations would be good and would make it easier for tooling and experiments in this field.

  • It would become possible to program (e.g.) TypeScript without compiling the source code. There would only be type checking at development time. This would considerably improve the development experience for statically typed JavaScript:

    • No intermediate files would be needed for execution.
      • This would be especially useful on Node.js where you could run TypeScript files directly.
    • No source maps would be needed to see the original source code while debugging.
    • .d.ts files often won‘t be needed either.

    This development experience is similar to providing type information via JSDoc comments – which is already a popular way of using TypeScript.

Downsides:

  • I like that right now, static typing systems such as TypeScript are completely optional layers on top of JavaScript and don’t add any complexity to JavaScript.
  • The proposal adds much new syntax to the language. Even if engines ignore it, they must still be able to parse it. Upgrading JavaScript tools will take time and effort.
  • If TypeScript (etc.) aren’t compiled to JavaScript before deploying libraries to npm, browsing source code written by TypeScript developers will become less pleasant for people who don’t like TypeScript.
    • To help with this, removing all type annotations from a file might become an operation supported by text editors.

Various thoughts:

  • Python’s type hints are similar to the proposal.
  • How would the proposal affect Deno? Does it provide any benefits for its TypeScript-centric approach?
  • The value of minification would grow for type-annotated code: more saved storage space and a bigger increase in parsing speed.
  • Using TypeScript as a strict superset of JavaScript would probably become even more popular than it already is. That means: no enums, no TypeScript-style decorators (but there is a proposal to add slightly different ones to JavaScript), etc.

I can understand if JavaScript developers are afraid of TypeScript taking over their language. However, this proposal will be as far as things will go w.r.t. adding TypeScript features to JavaScript. From the viewpoint of JavaScript engines, type annotations will be more like comments.

What are your thoughts? Let us know in the comments!

Thoughts by TypeScript team member @SeaRyanC  

[Source: tweet thread]

Here’s one way to think about this.

Would you ever intentionally ship unminified JS to your production website? Probably not

Do you write minified code today? Definitely not.

But is it useful to be able to run unminified code? Extremely!

Removing type annotations is the same thing. And just like your lint rules might enforce a style guide, your choice of type checker can validate type annotations you write.

Runtimes ignore both style and type “errors”, both of which vanish completely in minfication.

You could imagine a world where JS didn’t allow indentation. We’d probably write a compile-to-JS language (or many) that allowed indentation, maybe with style rules.

“Indentation in the browser” would be the idea of just allowing indentation, not re-implementing those style rules.

Thoughts by former TypeScript team member @orta  

[Source: tweet thread]

One angle I don’t think people have explored when thinking about ‘Types As Comments’ is how much modern JS development has moved to a ‘soft fork’ of the JS language for types/tools.

‘Types as Comments’ would allow a lot of TS codebases to move back towards alignment with JS.

The TS design goals are set up to ensure that TypeScript stays as an non-hostile ‘soft fork’ of the language, thus ‘JS + types’ as the one-liner. Now with ‘Types as Comments’ allowing for ‘types in JS’ to not be a fork but a legit subset instead of superset.

Tweets by various people  

  • @_nicojs: “Reading through [the proposal], it is clear that this is not going to be easy. It’s mainly hard to decide where type comments start and where they stop.

    For example: function foo(bar: baz) {} seems simple, but what about function foo<bar>(baz: { qux: corge }) {}?

    [...]

    Did you know that add<number>(4, 5) is valid JS? It makes sense when you think about it, just never did.”

  • @alexandereardon: “If I worked on a compiler and I was tasked with making things faster, I would be reaching for those annotations to help pre-optimise code as much as I could!”

    • Given that asm.js and AssemblyScript use type declarations to produce faster code, this idea seems plausible.
  • @AndaristRake: “The only benefit from my PoV is that I would be able to copy my TS code and evaluate it quickly in a console etc, without stripping the types first.”

Further reading