Hacker News new | past | comments | ask | show | jobs | submit login
The Great CoffeeScript to Typescript Migration of 2017 (dropbox.tech)
307 points by dgoldstein0 22 days ago | hide | past | web | favorite | 209 comments

I started reading through these comments expecting a tall wave of negativity, and was surprised to see such a warm wash of mixed and fond memories from the "bad old days" when ES3 and IE ruled the roost.

Full disclosure: I haven’t used it myself much since ~2012 or so, and modern JavaScript now contains many of the most important features that CoffeeScript offered at the time .... Although they did screw some things up (IMHO): null-vs-undefined in default arguments, super as a parent reference instead of a direct function call, optional parens for single-arguments arrow functions (Prettier agrees!), no shared semantics between arrow and normal functions, that class syntax only supports methods and not data as properties, and so on...

When all is done and dusted, I hope that CoffeeScript can be looked back on with affection as a little experiment that showed surprising vigor, one that — with no corporate backing and zero financial support — spread by word of mouth through the web community of the early 2010s, and helped fuel the fire to get JavaScript moving and evolving as a language again.

As a side note — and I write this without bitterness — I do find it a bit strange that extremely well-resourced companies like Dropbox, GitHub, CircleCI, Trello, Airbnb (and many, many more) would write so many hundreds and hundreds of thousands of lines of CoffeeScript without ever attempting to contribute changes or fix the issues that they wanted to fix. It’s open source! They probably would have been able to quickly and cheaply make most of the changes they wanted.

Anyhow, cheers for the blast from the past!

> As a side note — and I write this without bitterness — I do find it a bit strange that extremely well-resourced companies like Dropbox, GitHub, CircleCI, Trello, Airbnb (and many, many more) would write so many hundreds and hundreds of thousands of lines of CoffeeScript without ever attempting to contribute changes or fix the issues that they wanted to fix. It’s open source! They probably would have been able to quickly and cheaply make most of the changes they wanted.

This is the heart of a really important issue in OSS that affects everything good and bad about the scene.

There are companies that pretty much waste millions on poorly managed projects but won't donate the few thousand needed to make a lot of OSS projects succeed while still using the software.

It doesn't help that a lot of the culture just accepts fragile dependencies (who cares if this semi-crucial dependency is managed by the equivalent of newman from jurrasic park), and that a lot of the biggest OSS projects are usually made by people working at some big company. Maybe copyleft licenses would've prevented some of these issues, but I am not sure individual users like those restrictions even if, in some ways, it would benefit the community as a whole.

Its absolutely disgraceful how little financial support some really commonly used libraries get.

And "they don't contribute" is one of the _less_ harmful things. Look at what Amazon did to Elastic/search.

What did Amazon do to Elasticsearch?

Took Elastic's product (Elasticsearch), forked it and started selling it under the same name. It's a cautionary tale for anyone thinking about running a business based on OSS. https://www.google.com/amp/s/searchaws.techtarget.com/news/2...

Gotcha, thanks!

yeah; can you elaborate?

Reading this, I was intending to say that Jeremy Ashkenas should be publicly lauded for efforts in driving JavaScript forward. Then I saw your username.

Not to gush, but the profound difference Backbone, Underscore, and CoffeeScript have made to modern JavaScript development cannot be understated.

Thanks for all your efforts. They were exciting times indeed.

Thank you as well Jeremy, for helping us realize how useful JS could be with a proper stdlib in underscore, or how JS could be evolved with Coffeescript.

Part of the magic of JS in those days was observing how one OSS project (see: underscore, async, Q, Backbone, Node, Babel, Browserify, etc) could have such a profound impact on the JavaScript ecosystem.

Thank you so much for CoffeeScript! I bet on CoffeeScript in 2016 and surely would bet again in 2020, it is still great for those who want to focus on compact and clear coding. Your creation helped unknown developers like myself to actually find frontend coding bearable.

After seeing video with you talking about CoffeeScript design aspects ( https://www.youtube.com/watch?v=DspYurD75Ns ), it was clear that CoffeeScript was created by genius. I think the explanation why big corps did not contribute to your work is simple: they just could not. CoffeeScript was perfect from the start. It was ahead of time when it appeared and now it is still ahead of time for features you mention. It is like SQL or functional programming or algebra. Often best tool to get things done, but not for everyone.

If you ever read this, may I please ask one question? Imagine universe where all software is commercial. How much would CoffeeScript cost to its users?

I was a big fan of coffescript, it was way better than what ES3 offered. I did a small startup where everything was coffee, frontend and node backend.

The biggest issue was a little spacing between things would change meaning of program and things could go wrong. I lost some early customers because of reliability. That was a hard lesson and I learn the value of static typing.

Typescript is way more verbose but the lesson is you’re writing code so other people can use and improve it. That could also be future you. Dropdown and squiggly driven development that vscode offers is unbeatable as dev experience.

But coffeescript, like actionscript (Flash) has a special place in my heart. They were the big ideas back then.

Thank you jashkenas.

Thank you so much for CoffeeScript. I find it an ongoing pleasure to use.

I never bought into anything that goes far away from ecmascript. You need to think that any time you distance yourself from the real code, you make a compromise.

Coffescript has very little improvements at a cost (different syntax)

With typescript, it's also a compromise, but the benefit you get it's really good, types.

That's why moving to typescript makes sense, while coffescript not so much.

The post you're replying to isn't trying to get you to move to Coffeescript today. It's saying Coffeescript "helped fuel the fire to get JavaScript moving and evolving as a language again."

I truly do not understand why so many jumped from Coffeescript. I still use it and still believe I can be more concise and expressive in Coffeescript. Typescript and ES2015 picked up a lot of wonderful things, but I find myself writing a lot less boilerplate in Coffeescript. I will continue to "do me". I dev in Coffeescript and publish in JS. The project even made it a focus to transpile to readable/friendly JS. No biggie.

I would not publish things like this, though :)

console.log [ i if i % 3 and i % 5, 'fizz' unless i % 3, 'buzz' unless i % 5 ].join '' for i in [ 1 .. 100 ]

Separately, I bought overpriced raspberry pi's instead of cheaper alternatives because I knew the community was a strong source of support. Modern JS has a much larger community than Coffeescript 2.

The article literally provides you with the answers, from a front-end developer survey:

  Lack of delimiters
  Overly opinionated syntactic sugar
  Lack of community support for the language
  Hard to read because of dense syntax
  Prone to errors because of syntactic ambiguities
For me personally it was the last one. The actual parsing/interpretation behavior is undocumented beyond a handful of basic principles, and chock-full of edge-case ambiguities. Running into undocumented/unpredictable behavior literally daily in a language for me was a deal-breaker.

> chock-full of edge-case ambiguities

That is an issue... though I really, really love python because of it's lack of delimiters. It annoys me to no end switching from python to java, jscript, c#, etc. and forgetting a semi-colon or having a comma at the end of a list trigger a compile error.

I am the opposite. I hate python’s lack of delimiters. You move a block of code around when refactoring and suddenly what is part of an if or while is not longer part of an of or a while because the editor screwed up spacing. I would much rather have to deal with a compiler error telling me I need a brace, than a runtime error because code is unconditionally run when it was supposed to be a part of an if statement.

> forgetting a semi-colon or having a comma at the end of a list trigger a compile error.

I mean, these days though, I rarely have "compile errors". Meaning in-editor compiling is so good that any "red squigglies" get immediately fixed. Writing TypeScript in VSCode I can barely remember last time my actual compile step failed.

Well, that's basically because these days the editor often runs the same compiler, just without codegen instead of having a completely separate syntax checker that may or may not highlight the same issues.

Funny, I think Python's whitespace delimiters is one of the saddest design decisions it made. I know why it was made, and linting wasn't a think back in the day, but being able to properly reformat code with machines / compress code is so much easier with real delimiters.

You can skip semicolons in Javascript and Typescript in all but the rare cases where there is ambiguity. That's what I do and there is zero problem.

Am I correct in stating that standard Typescript no longer requires semi-colons?

Yes. This has been the case for at least two years now.

But don't please. Semicolons are not optional. When you don't put your semicolons, they will inserted by the parser and it can introduce some buggy code especially if you are using some formatter.

The behavior of ASI is fully specified. Semicolons are optional. There is no undefined behavior in the language spec that makes using semicolons somehow safer.

Furthermore, even if you always write semicolons you are still subject to ASI modifying your code by inserting additional semicolons where you don’t want them. So you need to learn the rules of ASI regardless of whether you use semicolons or not. https://feross.org/never-use-semicolons/

There is no ASI in “strict mode”. And modules are always in strict mode.

Edit: I was mistaken about strict mode.

That is just not true. You can write semi-less JS modules, strict mode and ASI are orthogonal.

Indeed, just read the spec: https://tc39.es/ecma262/#sec-automatic-semicolon-insertion

No mention of strict mode in the section of ASI. Could have sworn that the ASI issues I’ve ran into in the past was resolved by using strict mode, not sure what I’ve got that from.

Thanks for the link!

Can you show an example of such a bug? The only thing I can think of is

which will get flagged by TS as unreachable code (you can try it in https://www.typescriptlang.org/play)

I can't think of a good real world example atm but

Say, you have

    let a = 1
    let b = 2
    (a + b) <--- b won't be 
    accessible here. 
This will also get flagged by ts. But not everyone uses ts. /shrugs

Feross is right, I guess.

I think eslint would flag it as well for what it's worth (https://eslint.org/demo, you have to set it to newer ES version in the Rules configuration at the bottom of the page).

I just use ESLint + auto fix on save and I've never had to worry about semicolons for years, and even if i did it's not an error in JS.

I recall when we first adopted Coffeescript, the engineers who did it touted that we had about 20% fewer lines of code as an example of coffeescript being better - a lot of which was probably just the removal of lines that only had curly-braces. In hindsight, this wasn't a good metric to judge the language on.

As a larger engineering organization, what we've definitely learned over time is that we need to prioritize readability (and maintainability) over writability - as our code is going to last a long time and the original engineer who wrote it, will likely move on to another project, team, or even company. And while maybe they train their replacement, after a second or third iteration of that, the knowledge can easily end up lost.

Coffeescript, as a language, definitely prioritizes terseness, often at the expense of readability. And we didn't have internal coding standards that pushed back on this.

But even if we had done a better job using coffeescript, we're still better off in typescript today, due to the stronger community and stronger set of available open source tools to work with the language.

I see readability as a key advantage of TS. Once you are able to comfortably read type signatures, it is trivial to see what a function is supposed to do, or what a library is supposed to provide. When things don't work as expected, then it's just a matter of hopping into the debugger to inspect data inflight to find where the typings aren't matching up with reality.

yup, types are a huge advantage, especially in large codebases where you probably don't know all the people who may write code to interact with your code.

Readability of types can become an issue over time, but with the right naming of interfaces and useful type aliases, that can be mitigated to some extent. And as the typescript language and community evolve together, there are new ways to make some types even more readable - I've seen generics for getting the return type of a function, which seems potentially really useful (and some people swear by; I haven't used them extensively, but it looks like a promising idea).

After ten years of JavaScript and after working on TypeScript apps that have now been around for 5+ years, I can assure you TypeScript is less maintainable long term than most languages.

Did you know that TypeScript’s type system is turing complete? Good luck figuring out literal bespoke type frameworks in TypeScript. Did you know you can have a TypeScript application that takes more than 8GB of memory to compile?

TypeScript is literally a Microsoft play to regain Visual Studio market share they lost by creating a language that much like C# and Java, practically speaking, requires a massive feature rich IDE for most developers to write software efficiently with.

You all fell for it, and at this point it’s too late. Millions of extra development hours will wasted maintaining legacy TypeScript apps for years due to a Microsoft marketing stroke of genius.

If genuine developer satisfaction from everyone I know IRL who's used typescript is due to Microsoft's marketing, I say they deserve to win this one.

> where the typings aren't matching up with reality.

There are also libraries which provide runtime type validation, such as zod or io-ts. Can only recommend; they allow that in combination with typescript's strict mode your types become completely reliable.

Uh... welcome to static typing. Yes, it's nice.

It is not at all trivial to see what a function is supposed to do from its type sig. There are an infinite number of valid type safe implementations for:

    transform(a: number): number

It makes a number out of a number. Type signature isn’t supposed to explain the implementation, just the interface.

Something you run into when adding Typescript annotations to existing JS / libraries in the wild is when the signature turns out to be:

    function transform(a: number | string): number | "" | false
And it's usually all by accident. And it works because in practice it's used with a `if (!transform(x))` check.

Static typing doesn't just tell you what's going on, but it also helps you keep your implementation honest with your intent. It's also why it's a good habit to annotate top-level functions instead of relying on their inference.

You can sometimes use overloads to make it better:

    function transform(a: number): number
    function transform(a: string): false
    function transform(""): ""
Depending on how predictable the output is from the types, of course. But for many things it works better than just using union types everywhere.

This is especially true with `| undefined` helping address the billion dollar mistake.

Exactly. The parent post claimed:

> Once you are able to comfortably read type signatures, it is trivial to see what a function is supposed to do

Typing gives minimal insight into what a function actually "does".

The solution is intention revealing naming, available in all languages.

It doesn't really matter what the function does, if the input and output signatures are Interfaces or Types that have been annotated with JSDoc.

You see "Put an object with these properties and types in, get an object of this shape back out."

The beauty of types is in this black-box, abstract behavior.

You, as a library author, can define an Interface/Contract for the behavior of something completely abstractly, and other people can all use each other's implementations or contribute original ones because they obey the contract.

Think about an "Abstract class File, which implements open, read, and write."

There are a lot of ways you could write these methods but if your type signatures match the inputs and outputs they're all equally valid with predictable behavior.

Design by contract is a beautiful thing.

it matters when the function isn't pure but otherwise contracts are good.

Naming is where it starts, but the type signature also carries plenty of information it it, especially once you get to non-primitive types.

In my view, the primary advantage of CoffeeScript was to provide ways to avoid JavaScript footguns. I think that a combination of ES 2015 and wider propagation of best practices have made many such footguns avoidable in practice without using CoffeeScript.

But it brought along its own footguns. The article has one example

> For example, we had a major production bug in the fall of 2013 due to a misplaced space character.

Definitely my experience. Implicit returns are just a breathtakingly bad idea and I have personally witnessed them cause countless bugs.

I think they can be ok in a language where it’s been well thought out. Like implicit return in clojure has never bugged or surprised me.

Interesting, I've never heard complaints about implicit returns before. I really enjoy them in languages like rust. What kind of bugs?

I recall several resulting from the fact that lodash's _.forEach terminates iteration early if the function you pass it returns a falsey value for any element. Most people (myself included) weren't aware of this functionality and thought of the callback as a void function and weren't even thinking of what the last expression in it would evaluate to.

That just seems like a poor choice of api design for forEach, rather than a fundamental problem with implicit returns.

That matches my experience: the pitch was writing less, safer code but I found that JSHint (back then) had a comparable effect without a stop-the-world migration and a lot of the size reductions weren’t significant compared to following any style standards for naming, comments, etc.

I think it does depend on how familiar the syntax feels to each individual. To me Coffeescript is the right balance. I absolutely love writing Literate Coffeescript. I am _not_ a fan of strictly typed languages but I do hope Coffeescript finds a friendly syntax for gradual typing like TS in the future. I usually prototype in a 'ducky' way and then lock down type expectations when I'm polishing.

this is totally fair, but these days you are far more likely to find engineers to hire who know JavaScript or Typescript, than Coffeescript. This certainly matters more to larger projects and larger companies.

I can understand that people don't prefer coffeescript, but if someone "knows" JS or TS they could surely use coffeescript if they needed to do so... since we're still calling them "engineers" anyway.

Sure, but if there majority of your customers want a different language? You should probably listen. That's what happened here, and we are way happier for it.

You might even guess that the "old guard" could have been against such a migration. As someone who should have been a member of that, I wasn't a fan of changing... But then got a few rude reminders from debugging coffeescript that didn't mean what I meant to write. At which point I started thinking that maybe everyone else had a point.

Your comment above seemed to refer to constraints in the other direction: "we can't use Lisp because the only coders available to hire only know Java!" The point is, coffeescript and javascript are much more similar than that, especially now that javascript has imperfectly copied some of coffeescript's improvements.

It's not we can't use it, but rather using it for everything would make hiring, onboarding, and retention tougher, as well as maintenance.

Apologies if I have the wrong impression in the earlier post.

I don't use coffeescript anymore (primarily because I have grown to appreciate benefits of type-safety in larger projects) but miss it every other day.

It is especially tragic that despite the really awesome class syntax in Coffeescript, JavaScript went ahead with something so much more restrictive and as a result we have this whole multi-year fiasco on the right decorator syntax, incompatible implementations in babel and typescript etc. With CS class syntax it was trivial to wrap functions in higher order functions before attaching to the prototype so decorator like use-cases were trivially supported.

We still don't have a well supported syntax for bound member functions (Yeah, you can use arrow functions as member properties, but now you can no longer call super in them, the decorator syntax doesn't work etc. - something that trips up junior members of our team often).

Once you get used to everything being an expression, it is really hard to get back to the awkwardness of a language that distinguishes between statements and expressions. Over the last few months at work, I have been working more on kotlin (in JVM based projects) and it has been a refreshing experience although JS support is lagging behind and nominal typing is a poor match when transpiling to a dynamic language.

I feel like the only major innovation Modern JS offered that has significantly improved the DX was async/await. We are still languishing behind other syntactical enhancements that could drastically improve DX like pipelines and pattern matching and have simultaneously regressed to the ugliness of embedded XML in code (ok that is not part of official JS syntax, but not like we have good alternatives like kotlin builders etc. either).

Over the last week I have been experimenting more with Bolero [1] and it has been a good first experience. I didn't have a great experience with F# and Fable before, primarily because I felt F# was ill-suited as a language for targeting JS, but now with good webassembly support plus elmish, routing and remoting integration Bolero seems to hit a sweet spot in terms of DX, type safety and performance.

[1] https://fsbolero.io

I ported several large code bases off of CoffeeScript last year, mostly to JavaScript, but some to TypeScript. Simply being able to use ESLint is worth it (CoffeLint wasn't even close). I wrote CoffeeScript for years but I don't miss it one bit–especially now that TypeScript has optional chaining!

Personally I’ve also always found Coffeescript easier to read and more pleasurable to write because of its syntax, especially its reliance on white-space. But it seems this is one of those things that really divide people into two groups.

My only bug bear about coffee was its lack of a concise ternary, but it’s use of is/or/unless worked well for me.

I’m a bit sad that my Coffee/Pug/Sass/Yaml stack is supported out of the box in fewer places than it was, all sharing principles of less punctuation, and for me, more clarity as a result, but community support is pushing me towards migrating back to vanilla JS. Glad that some features are coming across, but things like destructuring aren’t as powerful (no [first, middle..., last]). Will be happy to see nullish coalescing come over.

I think the typing thing is relevant for big teams, something I’ve had the luck of avoiding for the most part.

Unless is hugely valuable to me, "do x unless y" is great when x should happen in almost all cases.

It avoids the noise of if statements, I really miss it in languages that don't have it.

I have a really hard time parsing `unless`. Whenever I encounter it in Ruby or CoffeeScript code, it takes me 10-30 seconds to stop and understand what's happening with the code.

Generally, postfix conditionals are a bad idea because they are garden-path sentences [1] by design.

Glad you find them valuable, but IMO they epitomize what many other comments in this thread have said about CoffeeScript's poor readability.

[1] https://en.wikipedia.org/wiki/Garden-path_sentence

I don't see anything common in structure between postfix `unless` and examples of garden-path sentences, which seem to be based on word ambiguity. Nothing is ambiguous in e.g. `print(x) unless x != 0`. Although admittedly without syntax highlighting, conditionality it's less obvious.

You're right, coffeescript's refusal to use python's more sensible ternary idiom ('normal' if condition else 'abnormal') is strange, especially since it already has the useful trailing-if idiom ('normal' if condition).

Same here, still using it for frontend (Ember and React) and backend work to this day and very happy and productive with it. Almost never have cases where I thought I needed more strictness or better community support. I am both more comfortable writing code as well as reading code in it, especially because it enforces significant whitespace and allows you to have more code on the screen because you omit a lot of filler stuff like braces, semicolons, bar/let/const etc. It's not for everyone but my brain is 100% in tune with it. Coffeescript, lodash and a functional approach to writing code are pure bliss to me.

I still have a soft spot for coffeescript, I think it's a very nice language to write. I don't use it simply because no one else at my company does. But at this point, like others have said, JS is much better than it used to be. You have the arrow functions and classes from coffeescript, and honestly, those were probably the strongest features. Although it can probably forever hold the lack of semicolons the javascript's head.

You know you can write JavaScript without semicolons, right? Or did you know, but also know that it can bite you?

I think it's just strongly frowned upon for not many good reasons.

Examples of how can it bite you I could find were really simple. Classic 'newline after return' doesn't go away if you put in semicolons manually because it happens because even if you put them in manually they are still inserted in other places you didn't expect and you have to be still aware of that.

The other bug I've seen is when you start a line with '(' which will be interpreted as function call of a function from previous line. Putting in semicolons at the end of each line saves you from that almost always easily detectable error. But you'd be just as safe if you just put ';(' at the begining of next line instead of '('. And I think starting a statement with '(' is weird enough and specific to javascript (in C family) that ';(' is not much weirder.

I use semicolons in js but for purely esthetic reasons so it looks like Java, C++, PHP, C# and such.

Having the last line of a function always be returned was one of the stepping stones to functional programming for me as it was now finally concise to write pure functions compared to pre-ES2015. Still post ES2015, if the arrow function body isn't a one-liner, you have to put back your curly braces and return keyword.

After a brief time in LiveScript, I've since mostly written in the ML families (Elm & PureScript) where this is the default behavior.

And I still like/use CSON over YAML in some cases.

You're right that one of the biggest reasons to switch is that everyone else has switched (which is a bit sad to me since I think Coffeescript had some good features to offer), and community support + developer tooling are always important factors to consider. We were on Coffeescript 2 which had niceties like JSX syntax support, but even then our team had issues with the lack of IDE support for it. We were using it with GraphQL/Relay which also meant we needed to maintain our own compilation toolchain.

In the end, the benefits of having types and first-class editor integration convinced us to switch fully which we did over the course of a few months towards the end of 2019. One of our team members even wrote a blog post about how we did it:


More power to you if you keep on using it, but maybe this can help explain the reasoning behind why we made the decision to switch.

As someone who was shamed out of using Perl, I can confirm that "more concise" isn't actually desirable at a certain point. Devs don't like verbose, but they also don't like obtuse. CoffeeScript is obtuse. To borrow a complaint from 10 years ago, it's like executable line noise.

So many moved because Coffeescript was old and typescript was new

Maybe some did. Many also moved because finally they could use a decent statically typed language on the client.

> I truly do not understand why so many jumped from Coffeescript

You clear up your own confusion right here:

> console.log [ i if i % 3 and i % 5, 'fizz' unless i % 3, 'buzz' unless i % 5 ].join '' for i in [ 1 .. 100 ]

And you said:

> I would not publish things like this, though :)

You just did though ;)

> I still use it and still believe I can be more concise and expressive in Coffeescript. Typescript and ES2015 picked up a lot of wonderful things, but I find myself writing a lot less boilerplate in Coffeescript

That boilerplate that you imply hinders conciseness isn't just boilerplate. It's code that helps you automate getting rid of certain classes of bugs. It also in most cases makes the code more readable IMO. And if the problem you are trying to solve is having to type less, I believe that's a job for your editor and tooling.

I stopped using CoffeeScript just because JavaScript fixed most of the issues that got me to use CoffeeScript back in 2014. Once ES2015+ became well supported, I decided I'd rather write code in the language that the interpreter understands, rather than something that precompiles. CoffeeScript isn't bad... it's just not significantly better than JavaScript is today.

Also, I find it interesting how many people like the Python syntax but hate CoffeeScript syntax. They have a lot of similarities.

As someone who works with Python a lot, Coffeescript always looked more like Ruby to me, especially with all the syntactic sugar (lack of parens, keywords like `unless` or `isnt`, #{} for string interpolation, etc)

> it was absurd to expect anyone to want this as their full time job for even a month or two

That gave me a true 'kids these days' moment...

In my day within a spanish bank, as a team of 4 interns, we spent over 6 months reviewing/documenting an entire proprietary platform C codebase (full of gotos, endian-dependent hacks, post-compile patches and every horrible thing you could imagine), and then with a larger (~3x) team about 12 months cleaning, porting and expanding that codebase to a clean platform (if you can call SCO Unix 'clean').

What sort of dynamics prevent a product startup like Dropbox build an engineering team that includes the capability to do such a task?

I didn't say people wouldn't do it. Some people actually did! the whole Maestro team, for most of Q2 2017, for instance.

Part of my point though is that converting coffeescript to typescript was very boring, mostly mechanical work (which is more obvious in hindsight, since we actually automated most of it). Sure, you could make the code better while you are there, but that actually was likely to add bugs, which could significantly delay such conversions, or lead you to chasing around the codebase to figure out how to get typechecking to work with your attempt at better types. What you are describing - going through an old codebase and figuring out how to fix it - sounds a lot more interesting! though definitely there are plenty of people who wouldn't want that job either.

But really the biggest blocker to executing on the manual conversion strategy was management. They already had other commitments for their teams, and spending a few thousand hours converting coffeescript to typescript wasn't as high of a priority for most of them, than the things their teams were actually working on. This partly comes down to our incentive structure - doing work for other teams, especially in a migration like this, can often feel like a chore, and is often not really rewarded with anything. But prioritization for a large project like this also takes a lot of input from upper management, and they didn't want to sacrifice other priorities to keep the original manual conversion plan on track.

I guess part of what you are saying is, that getting that task done was not so important for Dropbox in the grand scheme of things.

In the case I described, it was life and death for the entire organisation (proprietary hardware platform was EOL'd, so cero possibility of growth), and the managers that led it (and trusted 4 interns to do the ground work!) got rewarded handsomely AFAIK.

Thanks for a great writeup and clarifications!

Because startups tend to use how much you enjoy coding as a proxy for how good of a coder you are. So if you purposefully hire a bunch of people because they like coding, it's going to cause a shitload of problems once you unleash an "unfun" job like this on them for such a long period of time.

As a JavaScript developer this is limited only to everywhere.

As for myself I like coding, but what I really mean is I like writing original software to solve automation problems, which clearly not the same definition some of my prior colleagues have used.

Consider that I joined the bank as an intern and college student, but I had been programming for 10 years (almost 100% assembly) including two commercial video games published in my teens. And there was another like me in the team. We loved coding dearly, and 30 years later I still do (the other one pivoted into law, ah well). But work's work and must get done, right?

Wait what? So you should hire coders who don't like coding to do coding?

People who "like" coding tend to prefer hot new tech as a way of experimentation.

They often ignore the actual business problem that needs to be solved, because it can be solved using "boring" technology.

The thing is boring tech is often really just painful tech, where pain manifests in lots of different ways (error-prone repetition, painful manual testing, hard to read spaghetti code, etc). Programmers who are too insensitive to pain will continue to generate pain for themselves and others.

Seems like an invention on your part. I also sense some condescension towards this alleged group of people that you insist exists.

The reality is that people who like coding and thus trying new things are limited by the stack their job uses. Simple as that.

I don't really understand your hypothetical scenario where this alleged person is working on the new FooQux framework instead of getting work done. That's just someone who isn't doing their job. That they enjoying writing code seems irrelevant. Like trying to say people who like water skiing are awful employees because they're on the lake all day.

We need a word for this kind of HN trope. Condescension roleplaying?

My last phone screen, I emphasized that I like solving business problems, rather than tech for its own sake. They decided I "wasn't technical enough"...without asking me a single technical question.

That's the culture clash people frequently reference, and it's very real. If you don't perceive it, it's because you're swimming in it.

And I emphasize that the attitude, that the only good coders have tunnel vision and just want to play obsessively with tech, but only the cool stuff, goes far, far beyond the stereotypical SF startup environment or whatever. Because a large number of companies have a vague idea that to be cool, they should imitate what the trendy companies do, so even if you question the stereotype, the stereotype influences reality.

The most productive developer I currently have the privilege to work with isn't visibly passionate about the thing. She got back into this career after being a project owner for a few years and now just pushes forward like an icebreaker.

And the code isn't even "pretty" - it's just well-tested and is working as intended.

Makes one question some assumptions about what makes a good developer.

Maybe it's more about hiring people with a strong work ethic, who will do whatever needs doing, not just what's fun. Note: I don't think I'm really one of those people.

I would assume most engineers would like to spend time building stuff instead of migrating already built stuff to a different but kinda similar language.

I don't think it's unreasonable to not want to do a CoffeeScript to TypeScript migration full time for an entire year. It's basically the equivalent of creating a "tech-debt" team and giving them only tasks which pay down tech debt. Sure, there are situations where tech debt needs to be paid down and you could make an entire team do it for an year, but the engineers will probably not _like_ being on the team.

Someone being sympathetic about boring code migration work gave you a 'kids these days' moment...?

My take away from that was more that if you can avoid the manual labor do so, which seems fair enough to me.

The writer of the piece was not the "kid" in my comment. People who, by my understanding, would allow the work to remain not done because it was boring to do it, are. There's more clarification about the comment in the replies.

I fully remember picking up coffeescript because Dropbox had used it. I only ever used it on one project. I try and remember that every time I have the urge to go with Reason, Elm or even wasm compiling things. Long live JS.

If you are trying to build for a business, or something you yourself will have to maintain for years to come, vanilla JS seems like the way to go.

Perhaps Typescript isn’t a fad to be abandoned, unlike say GWT, CoffeeScript, et al, but why risk it?

Javascript doesn’t feel painful to me like Java does. I don’t have a lot of problems with it that need solving with an alternate front end.

Long live JS!

AFAIK TS is pretty committed (at the expense of possibly-useful functionality) to being very, very simple to strip out, leaving vanilla JS in its wake. Unless you're minifying, the compiler output typically looks almost exactly like the well-formatted, sane, and readable JS you'd have written instead. That escape hatch is part of why I've not worried a bit about taking it up. Turning a TS project into a JS project, should you ever need to, is functionality that's essentially built-in, and you do it every time you run "tsc".

But I don’t write “classes”, and don’t want to be lead down that path.

Allegedly TS has a solution for doing partial function application or currying, such as in the Ramda.js library, but the example that was provided to me a few weeks ago looked every bit as clumsy as the angle bracket stew in Java 8. I don’t remember the details, other than “I hope I never have to read that.”

PFA is like dependency injection for functions, without needing all the “executioner” class trapping nonsense, and with higher order function composition replacing much of the need for subclasses.

I guess deep down in my heart, I know that Typescript is coming to crush any joy out of working with JS. The industry of enterprise design patterns will demand it.

Some of you will understand this, but most will probably just hate on the unenlightened developer who must simply be resisting The Future. A “future” inspired by Simula67, with beans replacing copy books, and IoC provided singletons replacing individual .COB programs. Meh.

P.S. nothing personal. I’m simply terrified of the perception that TS is an unequivocal boon to programming-kind. It’s not, for all of us.

How does TypeScript push one toward classes any more than ES does? Does using typescript keep a person from using ramda? They list typescript typings on the ramda site.


“Fun” stuff to read. So if I want to write higher order functions, rather than classes / interfaces, I have to write, and worse, READ, mass boiler plate like the stuff in the link.

This feels like Java 8, to a large extent: you can use code that calls lambdas (e.g. Stream) but you don’t want to have to wade through such HOF code that has the needed cruft to use the callbacks. So in practice, people won’t create higher order functions and the like, as it becomes too much trouble to read and write.

What? Your tools do almost all the reading of types like that. It’s the entire point of using typescript: your tools tell you useful stuff with it. You’d never need to look at that file unless you found a mistake (bug) in the type definitions.

Though yes when defining your own functions you might need to take a second to write down what you intend it to do in a machine-readable way, so the next person who uses them can let their tools tell them what you intended, rather than memorized convention or docs or a comment somewhere or (quite often) just reading and experimenting with the code because that info is found no-where else at all.

When you’re calling such functions the “cruft” is minimal or totally absent. Definitions are where TS makes you put in a little extra work to get your intentions out of your head and down in the codebase for the benefit of your future self and anyone else who has to try to make sense of it.

Would I be correct in guessing that you are more likely to write an abstract class in the next month than to write a higher order function?

Part of the problem in these discussions is that there are at least 2 populations with vastly different work flows. Which would be less of an issue if I were part of the majority enjoying “mob rule”

> Would I be correct in guessing that you are more likely to write an abstract class in the next month than to write a higher order function?

I doubt it, because HOFs are hip in React-land right now and I don't really give a shit, personally, so I usually do whatever my team-mates find idiomatic in their current coding style and preferences, which means implementing and using HOFs, for now. Plus React picked "awkwardly add state and object-like functionality to functions by partially re-implementing objects" over "use built-in object system better, but tie react more strongly to OO-style programming" when they realized they had to pick one or the other to fix some problems, so React's even more functional now than it was before and is only heading farther that way as their chosen way forward continues to accrue functionality that OO-style React doesn't have.

Regardless, I haven't found TS to impede the writing of HOFs, and certainly not the use of them. I've been favoring them for a while even server-side just because it's "the thing to do" and other JS devs are familiar and comfortable with them these days and, again, I don't really care one way or the other. If I find myself on a team that prefers classes and objects, I'll use those instead in places where either would do.

Anyway, I'm more of a composition than inheritance guy when writing OO code. And I'd be more likely to define an interface than an abstract class. Not that I'd never, ever use the latter, it's just not something I reach for very often, especially in TypeScript.

[EDIT] actually, TS is part of why I no longer have significant preferences for how I write Javascript. Before, the only Javascript style I found not to be hair-pulling-out stressful and unproductive was about as C-like as possible, favoring a procedural style and aiming for zero indirection or "cuteness". Of course this was a popular JS style approximately no-where so this translated to my hating Javascript. TypeScript saves me from having to care. I'll write whatever, just give me types so I don't have to go read (or, god forbid, execute and poke around in) your code to figure out WTF you're doing even at the most fundamental level.

Yep, you can turn it into modern JS with something like `tsc --module ESNext --target ESNext`.

Part of our pain migrating off Coffeescript was that the compiler converted to ES3, not ES6. Which was fine for the browser, but not great for codebase quality.

Once you stop making hundreds of classes with globally visible names and members, and start using function scope, functional programming, and mostly short lived value objects, much of the OOP induced pain of programming simply goes away.

Alas, this requires training of the road not taken.

I don't know the details but I heard the original codebase was javascript but they used an automated script to convert it to coffeescript as an hack week project! That's some serious long term damage they did in that one week.

Edit: Found the 2012 post, pretty useful for doing a postmortem https://dropbox.tech/application/dropbox-dives-into-coffeesc...

I don't view it so black and white. While certainly parts of how we ended up using coffeescript weren't great and ended up causing lots of problems, in 2012 it looked like a net win - we got a bunch of new language features several years before they were actually standardized in any form.

It wasn't until 2015 that es6 came around, and we saw how things could be better; and typescript didn't have much momentum until 2015 either. Without a crystal ball, it'd have been very hard to predict this shift.

I wonder if Dropbox devs would say CoffeeSctipt was a net negative. The authors mentioned how it made supporting IE11 easier for example.

The devs that did it probably quit immediately after and started a consulting company where they advised all their clients on how to convert to coffeescript too

Since wasm has native browser support it doesn’t really feels like it fits into this group. I have a feeling in a few years wasm will be pretty common.

Yeah, wasm is offering something those others aren't. You could say that Coffeescript to Typescript is a lateral move. Try as you might, you can't do the things wasm is best for - say, graphics - in Coffeescript.

Does any alternative have any traction?

ReasonML is used by Facebook. Elm used to get more attention on HN.

Reason looks pretty cool but I'm weary given the outcome of flow

Reasonml claims, as an explicit goal, to output very readable and modern JavaScript, so it shouldn’t be such a risk. That task is a work in progress, but even looking at the latest recent release you can see that it’s coming along nicely.

Instead of TypeScript which is very far from being all-typed, I hope there will be wider adoption for proper Web languages like ReasonML[1], BuckleScript[2], PureScript[3], Elm[4], etc. With a better WebAssembly adoption and once they solve the garbage collection problem[5] and direct DOM access[6] there will no even need in JavaScript "glue".

[1] https://reasonml.github.io/

[2] https://bucklescript.github.io/

[3] https://www.purescript.org/

[4] https://elm-lang.org/

[5] https://github.com/WebAssembly/gc/issues/44#issuecomment-623...

[6] https://stackoverflow.com/questions/42628328/wasm-access-dom

Well, loose typing allows for far faster prototyping. I know some people will debate me on this, but mixing int and string in an array or returning an object or a string is far faster than going the 'proper' way. It's not great, but it gets you started earlier and that's a big point.

Another thing is that it's extremely easy to migrate from vanilla JavaScript to Typescript. You simply add a compile step at first, which breaks nothing, and then you slowly move your js files to ts while still being able to cross use them. I've migrated a ~10k LOC app and it was a breeze - whenever I needed to touch a module, I simply took the 5 minutes to make it TS. Whenever I touched a function, I added the type parameter. Being able to slowly convert a big app without ever having a major breakage or a massive change is something extremely valuable and rare (looking at you, `async`).

TypeScript just moves all errors from runtime to compiletime, even the ones nobody would ever realistically encounter. The user's browser is the only typechecker that matters, and that's why end-to-end tests are more important than type-linting.

Lol "proper". Type nerds!

I use coffeescript in 2020. It's a great language of choice especially if you come with a background of good programming languages like Ruby, Python, Elixir, Etc.

Coffeescript makes code more succinct, readable and javascript tolerable. I tried typescript, but, it's not my cup of tea and it has it's own quirks. I work with large scale media companies and never has coffeescript been in my way. If anything, it has made javascript bearable. These days, my choice is to avoid Javascript if I can and use something like Phoenix LiveView if I can get away with it.

I wish the coffeescript developers can ignore all the hipster noise and continue to support the project for their effort has saved so much valuable developer time.

I used CoffeeScript for a few years, and I went in deep. I loved the succinct and elegant syntax, it made coding in JavaScript a joy. I still think it's a wonderfully designed language with merit and worth.

When I decided to move on to ES2015, one reason was that JavaScript grew up, adopting some of the ideas of CoffeeScript, and the non-standard aspects of the latter became incompatible. (I recall some ECMAScript features couldn't be implemented in CoffeeScript, at least for a long time, due to existing syntax.)

A bigger reason was the mindshare of the developer community. When the majority adopted Babel and staying "future compatible", using modern language features that are guaranteed to be in the standard.

I want the code I write to be accessible to the majority, so more people can read, understand, and contribute to it. This is important for team work, such as easier onboarding of new members, so they don't have to learn a new (flavor of) language.

Choosing an "alternative" language also has long-term implications. When a developer moves on to a different project or company, they leave behind the code for others to maintain and develop. I realized that CoffeeScript would become legacy code, that someone will have to convert back to "normal" JavaScript eventually. I couldn't justify my developer convenience with that associated cost to others.

Funny enough, these days I prefer to write in TypeScript, another alternative flavor. I'm not "all in" yet, mainly because other developers at my work haven't picked it up. I have the impression that TypeScript is more of a standard than just a flavor, so I believe that writing it will not incur a long-term cost, but rather be a benefit, as more maintainable, type-safe(r) codebase.

Still, time will tell if that's true. Maybe I'm again contributing to legacy code, this time in TypeScript.

I worry about the long term viability of using an offshoot language of Javascript such as Coffeescript or Typescript. These types of languages have a habit of falling out of vogue and basically becoming a dead language, which is exactly what happened to coffeescript. If a company decided to write an app in coffeescript in 2010, today they have a big pile of code written in a dead language on their hands. If instead the company had chosen a mainstream language with a guaranteed future such as JS, Java, or c# it wouldn't be an issue.

TypeScript is the best bet in that regard, because not only it's backed by a large software company, but that company also builds all of its web apps (and now also Electron desktop apps) using TS. The sheer amount of buy-in inside Microsoft is such that I'd expect it to be maintained for a very long time even if there were no external users at all. But then this reasonable expectation that it'll still be there 10 years from now is also what's driving external users to it, among other things.

In fact, TypeScript is in PYPL top 10, and it's higher there than Go. It is a mainstream language now.

What do you mean by dead? It's still maintained and developed and still works great. Yeah, not many people are using it for new projects so if you're anxious about using something with the biggest "mindshare" then Coffeescript isn't for you, I give you that.

Typescript is nice in that it's a superset (mostly) of js. That doesn't mean it won't fall out of vogue, just that in a lot of cases converting from TS to JS is mostly straightforward, so you can "just" remove some type information and end up with valid JS.

You should be able to let tsc do it for you with a properly configured tsconfig file. Mostly just want it to not emit any polyfills.

> In 2012, we were still a fairly scrappy startup of about 150 employees.

Perhaps it's just the changing definition of the word "startup", but the idea of a 150-employee startup being described as "scrappy" made me chuckle.

I worked on this project, it was super fun. Open to answering any questions.

Any chance some of the codemon used could be shared?

I’m curious why not allow implicit anys instead of creating the tool that inserted anys? Seems roughly the same outcome but implicit anys would take a lot less work?

Because of the way we had type checking set up - our existing code already used noImplicitAny, and we wanted to keep that, and we were typechecking it all in one shot, together, so we couldn't have different typescript flags for different files.

Now as to why to use noImplicitAny in the first place: mainly because implicit anys are usually accidents - places where developers didn't realize they should put a type. And the explicit `any` in many ways is sitting there for anyone who cares to replace it with something better; whereas implicit anys are much harder to notice.

What was fun about it?

I personally think compiler tech is really interesting, and 90% of the project was writing transformations on ASTs. There's something about working in such an exacting environment where bugs are especially bad because they often manifest in subtle and hard to catch ways that's exhilarating. :)

As someone who came into development after the Coffeescript wave I’m interested to know: how much did it feel like the future?

Was it always an early adopter, “look how forward we are” kind of thing, or was it just popular with Rubyists?

I’m trying to calibrate it with other possibly-next-big-thing front end languages.

It was definitely popular beyond Rubyists - Dropbox was originally a python-based engineering organization, and we picked it up, and a lot of us liked it for a few years.

I think the main thing to note is that we were supporting IE7+ when we adopted coffeescript. So we couldn't even write standard ES5 - ES3 would have been the lowest common denominator supported. So having classes, optional chaining, array comprehensions, for-in loops that actually looped over items in an array (like ES6 for-of) - all those features were super useful. And you didn't need to worry about function declaration hoisting (or any confusion it could cause) because coffeescript only compiled to function expressions, which got bound to variables.

Unfortunately, coffeescript came with some others like implicit returns and tons of optional syntax that we didn't realize was problematic until far too late.

And being a python-based org, having a frontend language that looked similar (space-delimited, a lot of similar features e.g. array comprehensions were like list comprehensions, ternaries that looked more readable) seemed like features. But some of these features bit us hard at times, because they didn't work like python - the worst, in my opinion, was that `is not` and `isnt` looked the same but meant very different things in coffeescript. `is not` meaning `=== !` and isnt meant `!==`.

But given the alternative was writing prototypical-inheritance by hand, and dealing with various IE7isms directly? It was a sensible tradeoff at the time.

What’s wrong with implicit returns? I’ve always liked those in CoffeeScript and Ruby.

It can cause surprises. One of the biggest ones is turning a loop into an expression if it’s the last thing a function does.

Edit: here is an example


Accumulating loop results in an array is bad for perf, but won't necessarily cause logic bugs.

My favourite implicit return gotcha comes from the intersection of CoffeeScript and jQuery, where implicitly returning `false` from an event handler implies `preventDefault()` and `stopPropagation()`. This can even cause heisenbugs if your logging throws booleans around.

Another bad one: returning a jQuery.ajax object, and then consumers of your api may start using it directly.

We have that in our codebase still. Not sure if it was intentional or not but it's going to be hard to undo.

That's specific to Coffeescript. Implicit returns in Scheme don't do that.

CoffeScript had quite a bit of influence on JavaScript and TypeScript today (and/or really great timing w/ similar thinking). All of these were in early releases of CoffeeScript, and showed up in modern JavaScript years later:

* fat arrow functions

* classes

* template strings, multiline strings

* destructuring and ...rest values (splatting)

* elvis operator (foo?.bar?.baz - in TypeScript)

honorable mention

* list/iterator comprehensions (made some good progress in the ES speccing process, but ultimately didn't land)

I agree with some of items on your list but a lot of those features were part of ECMAScript 4 (ES4) which was largely abandoned in 2008 (with the exception of it being the basis of ActionScript 3). CoffeeScript's first commit was December 13, 2009.

From the Wikipedia entry ( https://en.wikipedia.org/wiki/ECMAScript#4th_Edition_(abando... )


By August 2008, the ECMAScript 4th edition proposal had been scaled back into a project codenamed ECMAScript Harmony. Features under discussion for Harmony at the time included:

- classes, - a module system, - optional type annotations and static typing, probably using a structural type system, - generators and iterators, - destructuring assignment, and algebraic data types.


I enjoy working in TypeScript in VSCode since it feels just like working in ActionScript 3 in FlashDevelop. except a bit slower.

I think it was also a forcing function for a lot of modern development patterns. Bundlers, sourcemaps, even chrome's prettyprint, all became mainstream around the time coffeescript was relevant (~2011?) I think they all existed before then, debugging coffeescript was a huge pain in the ass without them.

Yeah, is this sense Coffeescript didn't only feel like the future, it was a preview of the future.

ah, I forgot coffeescript had destructuring! yes, that is a great feature.

Probably the single biggest practical thing it did was fix `this` via `=>` when using jQuery or jQuery-based frameworks like Backbone.js. This didn't feel like the future so much as a fix for a giant painful wart in JS.

The second nicest thing about it was the way it eliminated a lot of ceremonial redundancy around code, parentheses in particular. Just like Ruby, it's not actually a great idea to leave those out due to ambiguities, but when you want a micro-DSL to encode some pattern, it really helps reduce the syntactic noise.

Third thing was being opinionated about how you structure classes and objects. This, again, didn't feel like the future; it felt like papering over a big gap in JS.

Yeah, just getting rid of the "interesting I guess but I'd never use them on purpose because they're just not helpful and likely to cause confusion or bugs" parts of JS, like direct fiddling with prototypally-inheriting objects (ew), worrying a bunch about what "this" means and shuffling it around for little to no useful reason, or entirely-unhelpful scoping rules. Most of those are better in regular JS now. For me, the syntax was at best neutral, leaning toward undesirable. I just wanted the extra ergonomics and safety, which didn't require such a departure from JS.

Some things still remain in the "future" bucket and I miss in JS/TS, like the native support for literate programming which lets you write your code and documentation together and generate e.g.:


I was at Groupon when we switched to 100% CoffeeScript. Honestly, it was a pain in the ass - from what I can remember there were multiple implementations of the spec that were supposed to do exactly the same thing, but occasionally didn't, which lead to weird bugs.

It had a lot of hype behind it, in much the same way TypeScript does now.

>Was it always an early adopter, “look how forward we are” kind of thing, or was it just popular with Rubyists?

Hard to say. Groupon still used it even after they ditched Ruby for node.js (and lost a whole bunch of engineers that wanted to continue using Ruby).

>I’m trying to calibrate it with other possibly-next-big-thing front end languages.

There is always another next-big-thing front end language/framework/library/tool. They all promise to change the world. I've personally used C with CGI-BIN, Perl, ASP.net, PHP (back when it was Personal Home Page), Java with servlets, J++ (the Microsoft "embrace, extend, extinguish" version of Java. Seriously, fuck Microsoft for doing this), J2EE, Struts, Seam, Spring, Struts2, SpringBoot, Jquery, AngularJS, Angular without TypeScript, Angular with TypeScript, React (and that whole ecosystem) and I'm sure I'm forgetting a few - every one of them promised to be "the future".

In the end, most front-end developers seem to spend half their working hours learning a new stack because of the constant change. This is fine - learning stuff quickly is part of the job, but sometimes I wish we would collectively take a pause for a year without any new frameworks, transpilers, meta-languages etc. etc. and just focus on seeing what stuff works best in the longer term.

I'd like us to collectively remember Antoine de Saint-Exupery's maxim "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." instead of adding three hundred "essential" node.js libraries on to the next CRUD app we build.

I think it's important to learn the basics well first. Just make some stuff with hand-coded HTML, maybe a bit of CSS, some forms (or AJAX-like calls if you must) and something on the server to do some processing on the stuff you send it and spit back a result. Or, even, just spend a bit of time appreciating the beauty of motherfuckingwebsite.com

I think CoffeeScript was definitely popular outside the Ruby community, too, for a while. (After all, Dropbox was/is a Python shop, not Ruby!)

Speaking strictly for myself, while I liked a lot of what CoffeeScript was trying to do, I didn't love the "one layer removed" feel of writing in a language that wasn't the one actually being executed. Also, I often found CoffeeScript to be cryptic in ways that vanilla JS, for all its quirks, really wasn't. So I think it felt like the future for a couple years, until JavaScript ES6 took off and it started feeling kind of superfluous -- ES6 felt like it was taking the good parts of CoffeeScript while leaving a lot of the quirks behind.

Coffeescript definitely felt soooo much nicer to work with than JS at the time. Writing in Coffeescript back in 2012 felt like Typescript does now, where going back to working in base JS felt miserable after using it. ES6 took a lot of ideas from coffeescript which basically made it redundant. I wonder if the same will happen to Typescript if types get added into a future version of JS? We'll probably have another post about switching a massive codebase off Typescript onto whatever the next big thing is.

This gets brought up a lot - but I work on both TypeScript and within TC39. Adding a type system needs consensus from the committee, and ideally we would never leave the existing community behind (because that'd be a standardization failure) and at some point someone will need to implement the static type checking portion.

Who would do that apart from existing type-checkers? A team like TypeScript, that's who. :)

TypeScript almost seems designed to be transitional, and I say that as a huge fan and heavy user of TS. Gradual typing is fantastic for learning, porting a codebase, and interop with JS libraries, but as TS gets more ubiquitous and everyone goes toward strict mode, people are going to start wanting runtime enforcement of types, and to stop adding a ‘type’ or ‘tag’ or whatever metadata key to all their objects. After getting a taste of a good type system, people naturally want to go all the way.

If TS doesn’t figure out how to provide this in a nice way, I imagine there will be a fork or a new dialect eventually, or JS will get types added natively like you say, and lots of people will move in that direction.

I got turned down at a job interview in 2014 because I couldn't code coffeescript. The guy interviewing me went on-and-on about how cool it was. It was exactly like how Typescript is today.

Personally speaking from what I saw around the internet and my own experiences with peers using it, it was contentious whether it was so forward-thinking or sufficiently differentiated to make it worth it.

Back in 2013/14 I remember on a couple of occasions being quite annoyed when I found npm packages that I wanted to bugfix were written in Coffeescript rather than plain old JS. It always seemed so unnecessary, and tended to push me towards alternative solutions.

Awesome! Thank you for this article.

Though I use it daily, my biggest criticism of TypeScript is that it's not opinionated enough. From inception it was designed as sugar on top of JavaScript but not a replacement, and therefor they decided not to make decisions outside of the ECMAScript specification.

The advantage to this is developer buy in, the downside is how annoying it is to work with at scale.

In a monorepo, running 10 compilers in watch mode because TS can only consume external source which is compiled to JS. You can't consume TypeScript source directly (which would be nice if you want to use github as a package repository).

But it's fine. I'm happy paying the cost to not use JavaScript directly, but I am disapointed because it could be so much more.

Have you seen Deno? Would it help with your issues?


There are project references and build mode, so 1 compiler for a monorepo also works.

CoffeeScript was an amazing companion to a Rails backend. While I did get bit a few times by unexpected CoffeeScript behavior (implicit returns and whitespace, ah!), it was substantially more beautiful and "developer happiness" than the options at the time (2014-ish).

CoffeeScript will always have a warm place in my heart, tho I do use TypeScript as much as possible now.

Author here, also willing to answer questions

Thank you for sharing! Any chance you could share some of the codemods used?

“Lack of delimiters“ is given as the most common complaint about CoffeeScript.

I’ve never written any CoffeeScript - Is this referring to the language’s Python-like significant indentation, or something else?

something else. More that `()`, `[]`, `{}`, and `,` in a lot of places in the language syntax were optional. And we embraced that... way too much.


  foo: 1
  bar: 2
is the same as

    foo: 1,
    bar: 2,
for basically no good reason. When you start combining a lot of these, whitespace takes extra significance, and in extreme cases can easily change what you think the meaning of your code is, and what it actually is.

Thank you for the article! Very interesting!

This makes me miss CoffeeScript. Ah, well.

Only thing I still miss is noop functions are two characters. Everything else I liked is in JS now that nullish coalescing landed.

`_=>_` is technically more than two, but not by much.

Identity function is more confusing than just ()=>{} which is obviously noop because it doesn't return the input.

If you don't provide an argument, it will use undefined, which is the same thing yours returns. Maybe it's more clear, but it's about even for me.

That bit was interesting:

>> Manually convert a list of ~100 commonly edited files from Coffeescript to TypeScript.

Seems obvious, but outlining it as a critical step probably helped in many ways.

Coffeescript tried to simplify the syntax, but it went too far.

- A statement such as f(g(x)) becomes absurd without parentheses.

- Indentation has a meaning, but it is legal to have inconsistent indentation.

Code is written once, read many times. Coffeescript got that backwards.

CoffeeScript is to JavaScript what Stenography is to Writing. Steno makes sense when you have to write something being dictated to you in real-time, but if you are not in a hurry, just write.

> A statement such as f(g(x)) becomes absurd without parentheses.

This was a feature I actually enjoyed.

- A statement such as f(g(x)) becomes absurd without parentheses.

Y'all just aren't used to ML syntax.

To me, having no parentheses is like driving on a 8 lane highway with no lane delimiters.

you'd really love lisp!


Though some of their constructs, like classes and for-in loops - are great for reading and writing.

Coffeescript does have useful features, but problems such as the ones I described made CoffeeScript code inconvenient to maintain in practice.

If we weigh the convenient aspects of CoffeeScript against the inconvenient aspects, in the end, CoffeeScript can be an inconvenient language to use. It was the case at least for me in various projects I had to maintain.

Part of the inconvenience was all the JavaScript tooling you cannot use, and occassionally being forced to read JavaScript code generated by CoffeeScript.

Yup, totally agree. In 2012 when we adopted Coffeescript, it was less cut and dry - all the open source tools we love now - prettier, eslint, etc. - didn't exist. So the tradeoff was less obvious then.

I loved coding CoffeeScript on my own a few years ago. Today the thought of having to review PRs written in CoffeeScript by my junior developers is terrifying.

My fond memory of CoffeeScript was an interview I did way back when at Olark. It was a full day 'paid work along' interview that was popular at the time. I'd never touched CoffeeScript prior. In less than the day, I was proficient enough even navigating a foreign code base to build out a small feature within the Olark platform. (I think it was managing chat operators as groups?)

Fond memories!

CoffeeScript rocks for functional programming. Less chars and more sense per LoC, easier to learn than JavaScript and syntax sugar is sweet.

Hmm. I wonder how much longer it'll be before they migrate from Typescript to the next fad version of JavaScript that comes along?

CoffeeScript? 2017?

I had the impression that CS was done when ES2015 came out in ... Well 2015

I personally prefered LiveScript, should have been.

They started the project of looking for a replacement language in 2015. You can't instantly rewrite all the code.

-can't +shouldn't

My co-worker of that time did exactly that one week before I got hired.

Also, he told noone.

I just saw it one time, when I played around with a tool that would visualize Git commits, years later. Thousands of lines of code.

Absolute mad lad.

CoffeeScript never made any sense. The drawbacks of having a build/bundling step and having to run/debug transpiled code were never worth the tiny benefits it offered.

I think the drawbacks of bundling are still not worthwhile even for TypeScript, but I'm not surprised that people who liked CoffeeScript would like TypeScript even more. It is unquestionably more useful; at least you get some value in exchange for having to spend most of your development time waiting for the build to finish.

What is mind boggling to me is just how popular CoffeeScript became. It makes no sense at all. I guess it just got a lot of celebrity endorsements.

I think the problem is that 'real programmers' held such prejudiced and condescending views of JavaScript that they were not willing to learn it and figure out best practices. They were too proud for JavaScript but they still needed to use it for their job so that's why they were prepared to use any possible alternative; better or worse - At least their ego was protected.

Same thing with TypeScript; its main purpose is protecting developers' egos by allowing them to leverage the power of JavaScript without actually having to admit to themselves that they're using JavaScript.

IMO, it's self-deception. JavaScript has proven itself to be an amazingly flexible, adaptable and backward-compatible language. It has flaws just like any other language but it's an objectively amazing language. It has proven itself.

Some developers will insist that it was because of JS's monopoly on browsers that it was successful but you'd be surprised by how many set top boxes and car navigation systems are powered by JavaScript (and they could have used any other language).

JavaScript achieved this in spite of being constantly undermined - The fact that it was able to grow and dominate in such adverse social environment speaks to how truly great it is as a language.

> the tiny benefits it offered

It allowed using language features that only now, nearly a decade later are commonplace. It offered huge benefits.

The only people I ever knew personally who used CoffeeScript also used Rails. That was usually the combo then.

The shine has kind of come off Rails, and the cool kids followed the shiny to the next thing, usually node, and so they moved to Typescript.

Still use coffeescriot when I need to do something quick. It has added all the async goodness of the more recent js implementations and it is still 10x easier to read and makes me 10x more effective.

I eagerly await the Typescript to SpoonScript (what have) migration of 2027.

I loved CoffeeScript... I just loved types more. If CoffeeScript had a type system akin to TS or Flow, I'd be in heaven.

I wonder what happened with the devs that started the tumble towards the Coffeescript migration... still locked in the cellar?

I don't think the CoffeeScript advocates did anything wrong at all. CoffeeScript was a popular solution with a healthy ecosystem, no one knew when JS was going to get these features, and TypeScript was still an emerging player (just like other typed JS variants like Flow).

Also, when I wrote in CoffeeScript, (1) I loved the JavaScript ecosystem more, (2) I understood the code I wrote better and built and learned more quickly, and (3) I understood the nuances of an JS-extension language, which helped me quickly understand what TypeScript was when I heard of it. I'd assume that other developers got some of these benefits as well, and these benefits may have been well worth the cost of converting from CoffeeScript later.

Is CoffeeScript all but dead? I use Ruby and Python a lot so the syntax of CoffeeScript looks great to me!

Lots of people use it (I use it for all my personal stuff) and it sees regular updates. [0] I think it coordinates well with modern client-side frameworks like Mithril (... and experts agree [1]). It has kept up with the new stuff in javascript, and it often does the new stuff better than JS. Example: in coffeescript you don't need the goofy function declaration flags that JS requires: "*" and "async". In coffeescript a generator is a function that yields and an async function is a function that awaits. This is clearly better.

Obviously, Typescript is more appealing to management. It may not be obvious from this thread, but bragging about how old-n-busted coffeescript is compared to... whatever was a lot cooler a couple of years ago than it is now. Nowadays the cool kids complain about npm or rollup or something.

[0] https://github.com/jashkenas/coffeescript/commits/master

[1] https://mithril.js.org/signatures.html#splats

I do Rails full time and most the CoffeeScript lives in the "legacy" side projects. Most projects I'm on have moved to vanilla JavaScript or ES6 via Webpack.

I don't think it's dead (it's still popping up), but I think it's time has passed.

Cofeescript will always be remembered as peak code hipsterdom.

You can easily test your Coffeescript code with a dynamic type checker and be perfectly type safe, even at runtime! Why for gods sake convert your code base to another language primarily for imaginary type safety?

But for some strange reason entire armies of developers move to Microsoft's Typescript, living their imaginary type save dream. Moving from a language as Coffeecript to Typescript is like dropping at least 25% of your productivity. Not only you'll have to write more code, which in itself increases the chance for bugs, but you'll also be fighting countless compiler issues, installing numerous @types modules, having intellectual discussions about types and whatsoever to make it 'kind of work'. Oh, and almost none of the TS code bases I've seen are without the 'any' keyword, which is actually an instant breach of your type safe haven. IMAO 'any' should never pass a code review in a Typescript project if you want to stay true to your religion. With such a strict regime, like you are forced to with real strictly typed languages, would completely eliminate TS. Without 'any' it's practically impossible to write a large code base with it.

I wrote numerous relatively bug free applications in Coffeescript, small and large as well. Just do good testing and you'll be fine, and as a bonus you'll have type safety at runtime! The mine field is not types IMAO, there is so much more to high quality code bases.

Using 'any' is perfectly fine, you just don't understand how most companies use TS.

Not using 'any' is also perfectly fine, as you can with Javascript, Python, Ruby, etc.. And I guess that most companies just don't understand how I use Coffeescript.

Besides, I am not against others using Typescript, it's a fun experiment and a great opportunity for front-end developers to learn about static typing, enjoy it if you can! For me it unfortunately doesn't work, I've never gained from it because I generally don't have type issues. It's a pain in the ass that's constantly bugging me, pulling me out of the flow. It's a monster of a tool that tries to solve a problem I don't have.

I agree that types don't add any value for most experienced developers but I don't understand why use CoffeeScript instead of plain JavaScript... Just a few more lines doesn't hurt and you save yourself from having a compulsory build step, dealing with source maps and dealing with transpiler version compatibility issues.

> I don't understand why use CoffeeScript instead of plain JavaScript

I didn't say I don't use plain JS today, I do! And indeed for the exact same reasons you mention :)

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact