In March 2022, a Stage 0 proposal was announced that would add TypeScript-like type annotations to the JavaScript language. The utility and ergonomics of static types for JavaScript have been debated since before TypeScript’s inception; some developers feel that types add needless complexity to the language, while others feel that types add a much-needed safety net. Today, static typing is one of the most desired JavaScript features, and adding some level of type syntax to the language would provide several benefits.

The proposal

In a nutshell, the proposal seeks to add a subset of TypeScript’s type syntax to the JavaScript language. Type annotations would be optional and would have no impact on the JavaScript code at runtime. Tools such as the TypeScript and Flow compilers could use these annotations to type check code. Browsers and other runtimes could treat the types as comments, completely ignoring them.

The scope of the proposal is very constrained. It describes a purely additive type syntax for JavaScript; the additional syntax would not affect the current semantics of JavaScript. JavaScript code would not be required to have type annotations, nor would runtimes be required to process annotations (beyond recognizing them as comments). Types would have no effect on code at runtime.

Why it’s good

Static typing in the web community has become increasingly popular over the last few years. TypeScript has ranked in the top 5 most well-loved languages for the last several annual Stack Overflow developer surveys. As static typing has caught on, packages that relied on externally maintained types are starting to manage their own types. It’s common to see messages like this when running npm install in TypeScript projects:

npm WARN deprecated @types/next@9.0.0: This is a stub types definition. 
next provides its own type definitions, so you do not need this installed.

Although static typing is popular, using it can still be a bit of a pain. Developers have two options: they can use a language that’s almost, but not quite, JavaScript, and that requires a build step (outside of the Deno runtime), or they annotate JavaScript using JSDoc or Flow comments. Both of these options add overhead to the development process, and that overhead is part of the reason types aren’t used more often. Even when a developer has adopted static typing for their own projects, they will often need to use packages for which types are an afterthought, or are maintained separately from the code by a third party. The types-as-comments proposal could help with all of these issues.

Baking types into the language would make them much easier to get started with and use. Running typed JavaScript wouldn’t require a build tool, which is one less thing developers will have to install and configure. Popular editors such as VSCode already come with support for handling typed code, so no additional effort should be required to make use of the types.

This proposal would also help in those situations where a build step isn’t convenient or isn’t possible. While many tools and workflows can implicitly handle TypeScript code, others cannot. In these cases, a developer that wants to use types must either pre-compile TypeScript code or add types using a comment-based syntax. Neither of these is very attractive; pre-compiling adds complexity to the development process, and comment-typed code is very verbose. Consider this snippet of TypeScript:

function loadData(url: string, limit: number): Promise<unknown[]> { ... }

When typed using JSDoc comments, it balloons into this:

/**
 * @param {string} url
 * @param {number} limit
 * @returns {Promise<unknown[]>}
 */
function loadData(url, limit) { ... }

The extra code is certainly worth it in many cases, but having types be part of the language would be significantly more pleasant. 

Adding a standard type syntax to the language could also spur development in type checkers. Python is a good example of how this might work. It has a standard type syntax defined in the  PEP-3107 and PEP-484 standards, and several high-quality type checkers have been developed based on those standards; two of the more popular are mypy and Pyright. Mypy is written in Python and is extensible via a plugin system, but it can be complex to configure and is relatively slow. Pyright, a more recent type checker written in JavaScript, powers VSCode’s Python language services. It is considerably faster than mypy, but lacks mypy’s extensibility. Because both of these are based on the same standard types, a project can use either one or even both (CI might use mypy while a developer’s editor uses Pyright).

Potential issues

As the saying goes, there’s no such thing as a free lunch. Adding types to JavaScript would have some downsides.

Obviously, the new syntax would increase parser complexity since the parser would have to handle new syntax elements. However, the impact would be minimal since the new syntax could be ignored. 

The new syntax could also make code harder to parse for developers. Fans of TypeScript would say this reads very well:

function loadData(url: string, limit: number): Promise<unknown[]> { ... }

Developers not so fond of static types would point out that there’s still more to read and process there than in the corresponding JavaScript:

function loadData(url, limit) { ... }

A key point to keep in mind is that types would be optional in this proposal. Developers would not be required to use types in their own code, and there would be no compatibility issues when using dependencies that did choose to use types. Editors could even conceal type annotations for developers that didn’t want to deal with them.

Although eventually, this proposal would allow for typed code without a build step, there would be a transition period where build tools were still required. Luckily, tools already used in most projects, such as the TypeScript compiler and Babel, could handle this.

When building is no longer required, some developers may choose to forgo code optimization and deploy typed code directly to production, resulting in wasted network resources. While this is certainly possible, it’s not a new concern; this situation can already happen when using comment-based types (which are significantly more verbose). Existing code minifier tools could be updated to remove types, mitigating the performance impact.

Possibly the most significant issue is the changes that might be required of TypeScript because of conflicts with existing JavaScript syntax. While JavaScript developers could simply ignore the additional type syntax, TypeScript users could not. Consider this example from the proposal: in TypeScript, it represents a simple generic function invocation, but in JavaScript, it represents a set of comparisons:

​​add<number>(4, 5)

A JavaScript syntax for generic invocations would need to be distinguishable from existing valid syntax; the proposal gives an example of prepending ::, like:

add::<number>(4,5)

TypeScript would need to understand the new syntax to process JavaScript files. It could likely support both syntaxes, as it does now for type assertions, where the legacy angle bracket syntax works in non-TSX files and the newer as keyword works anywhere. However, supporting multiple ways of doing the same thing adds complexity to the TypeScript parser and can result in confusing code when different syntaxes are mixed, so it would be in developers’ interest to eventually adopt the standardized type syntax.

Some TypeScript syntax will likely never make it into the JavaScript specification. TypeScript’s enum, namespace, and parameter property features have runtime semantics and so aren’t included. TSX syntax is specifically excluded in the new proposal since the base JSX isn’t valid JavaScript. And as the proposal works towards standardization other features like function overloads, which are useful for defining multiple types a function accepts, may or may not be standardized. These omissions would require developers to use a subset of TypeScript features to be JavaScript compatible.

Conclusion

On balance, the types-as-comments proposal looks like a net win for JavaScript. Although there are some potential drawbacks and compatibility issues, the most significant of them land on TypeScript rather than JavaScript, and Microsoft is in favor of the proposal. The ability to write typed code without requiring a build step, and to use typed code in situations where a build step is inconvenient, would be a huge win for proponents of static typing. On the JavaScript side, developers who typically avoid TypeScript due to its perceived complexity might be tempted to try out native static types, bringing the benefits of static typing to a wider audience.