I have been programming since the early 80s, and my experience with JS has been pretty positive, especially compared to the slog through the unreadable mud that is enterprise Java. (If I was going to rage quit on something, it would be the verbose, obtuse, repetitive Java sludge I’ve had to read the last decade and a half)
Typescript solves problems I don’t have. The Jetbrains IDEs do autocomplete just fine on vanilla JS, and the documentation window automatically shows the initialization and any JSDoc for most every symbol the editor cursor touches. I avoid writing code with thousands of global symbols.
OOP languages like Object Pascal and C++ are good for making lemonade from the lemon of manual memory management, but if you have efficient garbage collection, use functional programming techniques rather than OOP bloat, and many self inflicted problems go away.
I hope TS doesn’t turn JS into Enterprise Java, The Next Generation.
Nothing personal, most people seem to prefer that style. Just understand, there is a reason some people run away from the C++ / Java / C# / TS milieu.
No chance. And frankly, I don't get the comparison you are making to C++/Java/C#. TS is fundamentally different than those languages. From structural typing to a default functional/imperative paradigm, it really is just JS with better static analysis.
Your IDE is not as good for JS as it would be for TS. The entire impetus for TS is/was to provide better tooling/ergonomics around JS. Whether or not you need better tooling is a subjective matter.
I find that hard to believe because it's not a solvable problem without type annotations.
JS/TS are used in the Terminal's view layer. You can make services in these languages as well, AFAIK, but I don't think it is very common.
Just to expand on the conversion, whilst all of our apps (and hundreds of services) were migrated from C++ to JS, we still have much more C++ on the backend than we do JS. Thankfully it is not a language monoculture ;-)
edit: just adding though, that this isn't surprising with a dev base of 2000 js developers.
> Back in 2005, the company started migrating those apps from Fortran and C/C++ to server-side JavaScript
Since their use of Javascript predates Node (and the rest of that ecosystem, like Webpack or Babel or whatever), they've built up their own Javascript environment that doesn't rely on Node or Node conventions at all. Not so much a "get around odd shitshows" situation as much as a parallel evolution.
There was a long period of parallel evolution. Over the last few years we've been able to get back on the standards track. The article describes this as one of the guiding principles. It's why we participate in TC39.
Nowadays our tooling stack now uses TypeScript, Babel, Rollup & Terser which I regard as the most mainstream of choices. And we go out of our way to keep things aligned with ECMAScript, e.g. preventing the use of "experimentalDecorators".
My immediate thought is that by choosing JS, they attracted young (and cheap) developer.
ES Modules are the glue that binds the whole JS ecosystem together. Whilst ESM is the standard, today a lot of people are using ESM only as an authoring format that later gets converted to CommonJS before being published or executed. Many of today's tools rely on this, meaning the ecosystem is partially tied to CommonJS. Migration is happening but it's slow and non-trivial.
In a way, we bypassed the CommonJS era and skipped directly from AMD to ESM. AMD and ESM are pretty much isomorphic and differ only in syntax. You just run a codemod to get from AMD syntax to ESM syntax - semantics are preserved. Whereas the step from CommonJS to ESM does not fully preserve semantics. CommonJS module initializers are always synchronous. ESM can be asynchronous - you can use `await` in the module initializer.
The article covers a few of the things we've done to retain a very standard ES Module system that is ECMAScript compliant. I think it is this pursuit of standards and desire for robust interoperable packages that led to some of the surprising discoveries.
The fact that we can consider high-quality sourcemaps a solved problem (during both debugging and consolidated crash telemetry) really helps developers focus on building functionality rather than debugging a build system.
I think most large companies have dedicated tooling teams for these kinds of reasons. A related viewpoint in a related thread: https://www.reddit.com/r/typescript/comments/jrgi8z/10_insig...
Nothing to do with bugs, efficiency, etc... It's all about job creation so that companies can justify receiving more, bigger government contracts and loans on favorable terms from banks and they get more political influence by coercing their employees into voting for specific candidates (more headcount = more voting power).
It's true. The Big TypeScript lobby has been secretly working for years on a product called TypeScript Enterprise Edition. Many jobs will be created to support all those AbstractVirtualFactoryManagers.
Undeniable evidence: https://twitter.com/drosenwasser/status/1259946589902106624
This is just as serious as Bjarne Stroustrup's famous leaked interview in which he revealed why he created C++: https://www.stokely.com/lighter.side/stroustrup.html
Older libraries that are long abandoned by their maintainers usually don't have anything. At work we pretty much ignore all libraries that don't have types from somewhere these days, but that doesn't eliminate many things.
Having to write the definitions myself usually isn't a huge pain, but it's a big red flag showing that it's probably abandoned, and there's no community support around it anymore (or possibly ever).
It's rare for there to be a breaking change in the JS emit.
The TypeScript team work hard to preserve compatibility. Breaking changes are explicitly managed and communicated ahead of time. There is a concept of a breakage-budget per-release. This means if you stay up to date, the cost of each upgrade should not be huge. Orta and Nathan on the TypeScript team talk about this in this podcast episode: https://dev.to/devteam/devnews-s1e4-typescript-4-0-gitee-chr...
So "keeping up" is not too hard.
Also, for the cost of dealing with a breaking linter once and a while it helps enormously with upgrading javascript libraries provided they have up to date type definitions. If an API changes you are immediately alerted to many of the places where your previous assumption are now wrong.
It also completely changes the way you write code. Often time you can just go to the leaves of your application, make the change you want, and then just follow the compiler errors all the way back up to the top. When it compiles there is decent chance that it will run successfully first time.
That does seem a reasonable argument for avoiding enum types in TS. Those have semantics that go beyond how enumerations work in most languages and implementing them in the underlying JS is going to introduce some runtime cost.
I wonder whether their coding standards still permit const enums, though, as they are also new relative to JS but work more like traditional enumerations in C-family languages. These ought to be entirely compiled away, so it seems like the same arguments around efficiency and portability/compatibility wouldn’t apply.
enum is a keyword that is reserved in ECMAScript and therefore may one day clash with TypeScript. It's unlikely any ECMAScript-defined semantics for enum would match today's TypeScript enum. So it's not on any standards track.
There is already a proposal for JS enum that has different semantics to TS enum, and it was created by someone on the TypeScript team: https://github.com/rbuckton/proposal-enum
So the const form doesn't really change the hazard.
I wonder how likely it is that ECMAScript would introduce its own incompatible form of enum now that TS has become so popular. With static type checking as in TS, enums are very useful, but in the more dynamic environment of JS, the benefit is much smaller. So even if there’s nothing wrong with ECMAScript using its reserved keyword in principle, it feels like a bad idea to introduce a potential source of confusion and maybe subtle bugs when so many developers now use both languages.
Do you think this runtime cost will make much of a difference compared to everything else that goes on in the code? My impression that in the last few years the pure code performance is so fast that it almost doesn’t matter much anymore. Of course unless you manage to do incredibly stupid things.
The primary problem is the potential conflict with future ECMAScript. Multiple TypeScript team members have talked about how this feature is now regretted. The article features Orta's famous meme-slide communicating why runtime features (specifically calling enum) should not really be in the TypeScript language. Anders talked about it three weeks ago during the Q&A session at TSConf: https://www.youtube.com/watch?v=vBJF0cJ_3G0
enum is highly unlikely to be removed from TypeScript because of the strong commitment to backwards compatibility. But that doesn't mean we should encourage proliferation. Especially when many use-cases can be served more simply by string unions.
type Color = "red" | "blue" | "green";Perhaps not. It’s hard to imagine a program that you’d write in a language like JS in the first place where the small overhead of a look-up would be significant even for a feature as commonly used as enums.
However, there is a wider issue here than just whether to use one specific TS language feature or not. If you’re establishing principles that are going to affect thousands of developers working on thousands of different programs, which appears to be the case at Bloomberg from what I can see, then erring on the side of caution is a reasonable position to take. It’s difficult to objectively evaluate risk at that scale, whether from individually small but pervasive runtime performance hits or from potential future (in)compatibility with JS.
And that they use their own deno-like JS engine.
https://www.youtube.com/watch?v=ODgs0eWAIKc
The talk describes the system architecture and shows how the IDE is used to create applications.
Okay, I need another article about why in 2005 they chose to rewrite everything to server side JavaScript? That seems like, I don't want to say a bad decision that also led to all the issues and effort this article describes, but it kinda seems like it. In any case, it seems like an odd choice to make, especially in 2005, and especially coming from a fortran/c++ code base. So would love to hear about that and a retro on it.
It’s also important to keep in mind that Bloomberg is very willing to have their best developers go ahead and build actual tooling at the compilers (and language) levels to resolve issues they may face.
This occasionally leads to issues when they start diverging from the mainstream too much, but they’re also good about then stepping in and pivoting back to the mainstream development branches, which is kind of what’s happening in this article.
> Having worked there the JS ecosystem was a tremendous advantage
How so? And to maybe ground my question, in 2005 I'd have expected a switch to Java, C# or Scala. So what advantages were there compared to those for JavaScript?
> It’s also important to keep in mind that Bloomberg is very willing to have their best developers go ahead and build actual tooling at the compilers (and language) levels to resolve issues they may face
That's awesome, but from my read of the article, seems like a lot of fighting to rebuild things that Java just has. And now this whole move to TypeScript to backfill in types, again, it appears to me like maybe if they'd gone with Java, much less time would have been needed on the devs building their own tooling, compilers and doing massive project migrations.
Until then this is as much as I can share right now: https://news.ycombinator.com/item?id=25068119
Also to be clear, we don't have a language monoculture. The app layer and hundreds of services use JS/TS. But the majority of the backend remains C++.
I'd be very interested in an origin story. The emphasis on tight feedback loop is very novel for the time I feel, over going with Java for example, which could have been a middleground between feedback loop and type safety with much more tooling available at the time. And now with bringing types back in, slowing down the build times again, hurting the feedback loop, but it seems safety has now been favored over it, was it a change of heart, what lead to that?
Anyways I'll patiently await a maybe blog post about it :)
Thanks for the right up here, was very fascinating.
Why do they generate .d.ts files instead of publishing .ts files alongside .js files? This should solve inlining issue, no?
It's true you could just have every package publish the raw TypeScript source-code. So that when an app imports a library, it type-checks against the original source code of the library. No need for DTS files from your dependencies!
I have never seen this done in practice for a large system. It's not as scalable as using bare-minimum type declarations that you find in DTS files. It requires more parsing, and potentially more time to accumulate the types. Whereas DTS emit in TypeScript can flatten the resulting type into the DTS file.
But if performance didn't matter, I think this would probably work. And it would eliminate the class of bugs where the generated DTS files are not 100% semantically identical to the original source code. That's another edge-case finding I omitted from the document but hope to write up another day.
A developer with clean/fresh clones would still notice a big performance difference, but amortized over a number of builds it might not matter in general practice. In theory at least, as Bloomberg notes projects and incremental builds are still newish and don't yet always have the performance characteristics they should have in the wild. That said, the impression is that a lot driving projects/incremental compiles is monorepos in Microsoft (at the very least) that have moved to/are moving to monorepos that are entirely TS only builds with few/no DTS intermediaries. (That's just me reading between the lines, of course, I could be mistaken.) The drive behind projects/incremental compiles sounds like it is attempts at massive scales of TS files.
https://devblogs.microsoft.com/typescript/announcing-typescr...
The TS team was adamant they wanted to not be a runtime, i.e. it was JS + Typing only.
Partly I wish they just dumped ECMA and just made TS proper, but perhaps that's just Dart.
JavaScript is bound by backwards compatibility. It is expressed by the soundbite "don't break the web". I would love for typeof null to not be "object", and it seems appealing to say "well if JS won't fix it, maybe TS should."
The problem is that this outcome has many negative effects including loss of trust. Orta (a member of the TypeScript team) describes this exact scenario in his video "How Does the TypeScript Team Try to Avoid Negative Effects on the JS Ecosystem" in which he talks about TypeScript "Embracing and Extending" JavaScript: https://www.youtube.com/watch?v=qr0TnQ2mHwY
The TS team seem to be firmly going in the direction of ECMAScript alignment and the JS + Types model, which is something the article advocates for too. Overall this increases my trust in the technology.
On a related topic Bjarne Stroustrup once said "There are only two kinds of languages: the ones people complain about and the ones nobody uses."
That said, it's MS, not some side project. They could feasibly take the road to 'pure TS' especially now that they have the core following and MS has some brand trust.
There's probably a huge following of folks that would jump on a Pure TS train as long as it wasn't cloistered by all the .Net legacy.
Like PureTS on Mono VM type thing.
This is the kind of work that gets me excited to live every day.
This really shows though, to the point of the article, that TypeScript at scale really lives up to its name, albeit with some quarks (and in this case, some of those quarks are also due to the environment it operates in). I have also found over the years my experience has been positive when you adopt, most notably, the points about keeping all your packages across projects/repos up to date, particularly keep your TS versions rolling upward to prevent definiftion file incompatabilities is necessary.
I'm curious though, as I'm sure there are several authored libraries (not every repo I assume is a pure app), do you guys run into issues where you have to use a lot of complex typings (like using a function type to infer a given type even though the type you're inferring isn't a function, and other type dances) or has this not been the case? I've not had much of an issue with this, though I've had to do some pretty complex extends [[type]] ? stuff to get it to infer correctly in some situations where I want things to be as generic as possible.
This was an informative and interesting read, and I'm grateful you guys published it. Keep up the excellent work!
It's true the codebase has some gnarly advanced types (generic, conditional, mapped) for expressing types for constructs created prior to TypeScript being introduced. I suspect we are pushing the limits of the compiler - quite literally TypeScript has fixed limits on recursion depth that have caused us breaks in the past. Hopefully as we refactor code with TypeScript in mind we can reduce the overall type complexity.
And only because you asked... if you wish to join us, please check out https://careers.bloomberg.com
I wonder if they have published those rules, I'd like to see them as I'm just diving into TS.