https://effectivetypescript.com/2023/09/27/closure-compiler/ Effective TypeScript The Saga of the Closure Compiler, and Why TypeScript Won Wed 27 September 2023 [240px-Closure]Here's something that makes me feel old: in just six months, Gmail will celebrate its 20th anniversary. If you weren't actively developing web sites at the time, it's hard to capture just how revolutionary it was. This was a time when JavaScript was held in almost universally low regard. The idea that you could build a sophisticated web app using it was mind-boggling. But it clearly worked and it heralded the dawn of the single-page web app (SPA). Behind this application was an exciting new tool that Google had built for creating large JavaScript applications: the Closure Tools (that's Closure with an 's', not Clojure with a 'j', which is a different thing). This included the Closure Compiler (CC), a JavaScript source-to-source compiler that did type checking. Sound familiar? Unless you've worked on frontend at Google at some point in the past 20 years, it's unlikely that you've ever encountered the Closure Compiler. It occupied a similar niche to TypeScript, but TypeScript has absolutely, definitively won. Still, it's interesting to revisit CC for a few reasons: 1. By looking at a system that made different high-level design decisions than TypeScript, we can gain a deeper appreciation of TypeScript's design. 2. It shows us missing features from TypeScript that it might not have even occurred to us to want. 3. It's an interesting case study in the history of JavaScript. In other words, the saga of the Closure Compiler gives us some perspective. TypeScript has become so ubiquitous that it's sometimes hard to imagine any other way of adding a type checker to JavaScript. The Closure Compiler shows us that the design space was larger than it looks in retrospect. I wrote Closure-style JavaScript at Google most heavily from 2012-14. This post reflects Closure as it existed at that point. I'm much less familiar with how it's evolved since then. What is the Closure Compiler? TypeScript's motto is "TypeScript is a superset of JavaScript". Closure code, on the other hand, is JavaScript. It doesn't add any new syntax to the language. If you've ever used TypeScript with --checkJs, it's a similar idea. Rather than adding types to JavaScript through new syntax, you add them via JSDoc-style comments. Compare this TypeScript: function max(a: number, b: number): number { return a > b ? a : b; } to the equivalent Closurized JavaScript: /** * @param {number} a * @param {number} b * @return {number} */ function max(a, b) { return a > b ? a : b; } An invalid invocation of max will result in an error: > google-closure-compiler "--warning_level" "VERBOSE" "max.js" max.js:12:16: WARNING - [JSC_TYPE_MISMATCH] actual parameter 1 of max does not match formal parameter found : string required: number 12| console.log(max('foo', 'bar')); ^^^^^ max.js:12:23: WARNING - [JSC_TYPE_MISMATCH] actual parameter 2 of max does not match formal parameter found : string required: number 12| console.log(max('foo', 'bar')); ^^^^^ 0 error(s), 2 warning(s), 100.0% typed function max(a,b){return a>b?a:b}console.log(max("foo","bar")); This is similar to what tsc does in some ways but different in others. Just like tsc, it reports type errors in your code. And just like tsc, it outputs JavaScript (the last line). At a high level, type checking and JS emit are also the two things that TypeScript does. There are some interesting differences, too. The Closure Compiler reports that our code is "100.0% typed". Using TypeScript terminology, this is a measure of how many any types you have. ( Effective TypeScript discusses using the type-coverage tool to get this information in Item 44: Track Your Type Coverage to Prevent Regressions in Type Safety.) The other interesting difference is that the output is minified. This gets us the fundamental design goal of the Closure Compiler: producing the smallest JavaScript possible. Minification as Design Goal When Gmail came out back in 2004, network speeds were much, much slower than they are today. The Gmail team found that runtime JavaScript performance was almost irrelevant compared to download times. If you wanted to make your page load faster, you needed to make your JavaScript bundle smaller. So this is the central goal of the Closure Compiler and its "advanced optimizations" mode. To see how this works, let's look at some code to fetch and process data from the network. Here's an "externs" file (the CC equivalent of a type declarations file) that defines a type and declares a function: // api-externs.js /** * @typedef {{ * foo: string, * bar: number, * }} */ let APIResponse; /** @return {APIResponse} */ function fetchData() {} Some interesting things to note here: * Types are introduced via @typedef in a JSDoc comment. The APIResponse symbol exists at runtime but is not particularly useful. Just because CC is JavaScript doesn't mean that the JavaScript always makes sense. * The declaration of fetchData includes an empty implementation. TypeScript would use declare function here, but this is not JS syntax. So CC uses an empty function body. Here's some more code that fetches data and processes it: // api.js /** * @typedef {{ * longPropertyName: string, * anotherLongName: number * }} */ let ProcessedData; /** * @param {APIResponse} data * @return {ProcessedData} */ function processData(data) { return { longPropertyName: data.foo, anotherLongName: data.bar, }; } const apiData = fetchData(); const processedData = processData(apiData); console.log(processedData.longPropertyName, processedData.anotherLongName); Because it's just JavaScript, this code can be executed directly, presumably via a