I liked the idea of TypeScript, a tool that makes JavaScript more predictable and manageable. An introduction from Codecademy's Learn TypeScript course was quite instructive, but I knew that wasn't the whole picture. To learn more, I decided to read through the TypeScript Handbook. It is a document meant to be shorter and easier to read than the formal TypeScript language definition, at a tradeoff of less precision and skipping over details on edge cases.

The majority of value in TypeScript is in keeping track of code intent by assigning data types to variables. At first glance I thought it would be helpful but not a huge deal, but I was wrong. TypeScript can infer a lot from these type assignments. My favorite example was named "Exhaustiveness checking", where TypeScript could infer when a switch() statement is missing a case. This is a class of problem I frequently try to make visible in my own code. Unfortunately, I could only log an error and/or throwing an exception in case I fall into default. Which is a runtime solution where my code would come to a screeching halt long after I wrote it. But with TypeScript exhaustiveness checking combined with TypeScript 'never' Type, I could turn such mistakes into compile-time error "is not assignable to type 'never'". This is huge and this capability alone is enough to turn me into a TypeScript fan.

However, TypeScript can't solve all JavaScript ills, because TypeScript always maintains full runtime compatibility with JavaScript. This means TypeScript labels like "readonly" only communicates intent for compile-time checking and could not guarantee the value will remain immutable at runtime. It couldn't solve the fact JavaScript evolution ended up with a very convoluted model on what "this" means. Sometimes TypeScript tries to solve a problem, only for JavaScript to end up with a different solution to the same problem. Such as TypeScript labeling class members as private (intent-only compile time check) and JavaScript's "#" private marker (actual runtime enforcement?) And if JavaScript changes how inherited fields are initialized, TypeScript must follow suit while doing their best to provide a mitigation for existing code.

Another area where TypeScript had no choice but to follow suit with JavaScript is adopting all the different ways a function could be declared. My eyes started watering as I read through the function section of TypeScript handbook, I had never even seen most of these ways! Designing TypeScript so it could annotate type information on all of these function declaration methods must have been a huge headache. But this was just a taste: there's a whole "Type Manipulation" section of the handbook describing how to carry type information through all kinds of different convolutions. The author seems proud of this capability, claiming "we can express complex operations and values in a succinct, maintainable way" but I got lost. This is information I could not absorb on the first pass and would have to return frequently as reference.

Since the "easy to read" handbook already lost me on several points, I don't think I'm quite ready to jump into the full language specification just yet. But there was one more item I wanted to look up: class decorators are used in Angular to create every component, and I didn't quite understand how that worked. TypeScript reference page for decorators called it an experimentational feature of TypeScript that is also a proposal to JavaScript, which means things might change in the future if JavaScript officially adopts decorators in a way incompatible with what TypeScript does today. Oh well, if that happens, I'm confident the TypeScript people are well practiced at dealing with it. In the meantime, I have to devise a plan for my own TypeScript practice.