The Great CoffeeScript to Typescript Migration of 2017
dropbox.tech
dropbox.tech
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!
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.
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.
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.
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.
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?
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.
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.
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.
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.
Apologies if I have the wrong impression in the earlier post.
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).
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.
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.
transform(a: number): number 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.
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.> 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.
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.
> For example, we had a major production bug in the fall of 2013 due to a misplaced space character.
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.
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.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.
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/
Edit: I was mistaken about strict mode.
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.
return
value
which will get flagged by TS as unreachable code (you can try it in https://www.typescriptlang.org/play)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. /shrugsFeross is right, I guess.
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.
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.
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.
It avoids the noise of if statements, I really miss it in languages that don't have it.
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.
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:
https://dev.to/alexandras_dev/decaffeinating-2020-migrating-...
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.
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.
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.
Also, I find it interesting how many people like the Python syntax but hate CoffeeScript syntax. They have a lot of similarities.
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?
They often ignore the actual business problem that needs to be solved, because it can be solved using "boring" technology.
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?
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.
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.
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.
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.
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.
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!
My take away from that was more that if you can avoid the manual labor do so, which seems fair enough to me.
ReasonML is used by Facebook. Elm used to get more attention on HN.
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!
Alas, this requires training of the road not taken.
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.
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.
“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.
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.
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”
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.
Edit: Found the 2012 post, pretty useful for doing a postmortem https://dropbox.tech/application/dropbox-dives-into-coffeesc...
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.
[1] https://reasonml.github.io/
[2] https://bucklescript.github.io/
[3] https://www.purescript.org/
[5] https://github.com/WebAssembly/gc/issues/44#issuecomment-623...
[6] https://stackoverflow.com/questions/42628328/wasm-access-dom
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`).
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.
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.
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.
In fact, TypeScript is in PYPL top 10, and it's higher there than Go. It is a mainstream language now.
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.
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.
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.
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.
Edit: here is an example
https://coffeescript.org/#try:-%3E%20%0A%20%20for%20i%20in%2...
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.
We have that in our codebase still. Not sure if it was intentional or not but it's going to be hard to undo.
* 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)
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.
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.
Who would do that apart from existing type-checkers? A team like TypeScript, that's who. :)
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.
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
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.
CoffeeScript will always have a warm place in my heart, tho I do use TypeScript as much as possible now.
I’ve never written any CoffeeScript - Is this referring to the language’s Python-like significant indentation, or something else?
E.g.
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.>> 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.
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.
It allowed using language features that only now, nearly a decade later are commonplace. It offered huge benefits.
- 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.
Though some of their constructs, like classes and for-in loops - are great for reading and writing.
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.
This was a feature I actually enjoyed.
Y'all just aren't used to ML syntax.
Fond memories!
I had the impression that CS was done when ES2015 came out in ... Well 2015
I personally prefered LiveScript, should have been.
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.
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.
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.
I don't think it's dead (it's still popping up), but I think it's time has passed.
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
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.
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 didn't say I don't use plain JS today, I do! And indeed for the exact same reasons you mention :)