Joining the TypeScript community
Downsides and upsides
Intro
Prior to joining Hyperfish, I had very little exposure to TypeScript. JavaScript - sure - but TypeScript not so much. There is definitely a learning curve even though JavaScript (usually) works just fine if you change the extension from .js to .ts and kick it through typescript's compiler. The fact is that the languages are different, have slightly different communities and conventions, and the things you think about while building in them are different. In TypeScript you get to focus on your logical structures (types) and class interfaces, while in JavaScript you have to think very hard about code flow and general organization. Right now I am building microservices in TypeScript and shipping them in Docker.
The community I am coming from
I've previously enjoyed building services in Scala. One of the most valuable lessons that taught me was that community matters. The language road map matters too. With more mature languages like Java and C++ you never even think about this because they are so ubiquitous, and generally stable. In Scala there were tons of poorly maintained libraries, and unresolved gotchas in the compiler that when you encountered, you simply bookmarked the issue in Github.
The TypeScript community
So entering the typescript community I started looking at the TypeScript repository, what their mission statement was and where they are planning to go. TypeScript is sort of self-aware about points which may stop adoption, but here are some things I take note of:
- TypeScript does not want to generate JavaScript so much as type check it, and spit out very readable javascript. The extra syntax of TypeScript which makes it a superset of JavaScript is strictly to further the goal of adding a type system.
- To that end, it really avoids polyfilling features - because that would be generating new logic.
- However, practicality is king. TypeScript 2.1 ships with async/await support with a target output as low as ES3, which is only possible with a polyfill.
- Sticking with "practicality is king", the type system is not perfect, nor was it meant to be. But it is easy to learn and generally unambiguous, without the screaming complexity of other languages.
- There is excellent support for TypeScript in Visual Studio Code, Atom, Sublime, and more. It is very easy to edit across a team.
- TypeScript is hyper-aware of issues involved in meshing with regular JS projects, and constantly works to improve migration and quality of integration.
The actual people in the TypeScript community are awesome. They tend to be very professional, helpful, and courteous - seriously considering your problems as something that should work. Even if it wasn't originally part of the design. Maybe something isn't possible the way you think it is - they will still help you find a way to do your job. There are also a few super prolific characters in the community who constantly write about, promote, and build examples for TypeScript - I often refer to basarat as an example.
So where's the rub?
TypeScript has historically been challenging to use with regular JS libraries, because they are typeless. This means you import a library, and after having a clean intellisense experience for the rest of your code, you now have to actually go read the code or the docs to figure out function signatures and then say a prayer that your code will actually run correctly. This really stinks. The way we fix it is by writing special type declarations, .d.ts files, which specifically outline the types of a module. After a while building with typescript, everyone sooner or later writes their own typings in a pinch just to make sure they didn't mistype their code. This introduces the possibility of those typings not matching the javascript library should it change, which can be a painful situation to remedy. Especially if you are using typings from a third party for a different third party library. The day you decide not to upgrade a javascript library because typings are not available for it is a sad day indeed.
There is a ton of work going on in the typescript community to help fix this, and generally the problem is easily smoothed over. Use the typings or tsd, or use the most recent solution at this point which is to install types from npm using npm install @types .
Why does all of this matter?
In discussions with JS programmers who use babel and test everything to oblivion, they often say they do not see the added value of a type system. Their tests catch simple run time errors, because they unit test everything, because they use TDD. This is true if the tests are flawless, and they can even argue that the mistakes in typings are roughly equivalent to the nooks and crannies that tests sometimes miss.
There is a fundamental issue with this discussion - one which seems highly controversial - which is whether or not that test code is added technical debt. The answer to me is simply that there is more code, so yes, there is new debt introduced. Maintaining tests can be a nightmare. Running tests on large systems can be slow, and really - not everyone has the luxury of testing every trivial function just to be sure it will actually be able to run when it is invoked.
Testing is still important, but for critical code paths, not for every code path. Using TypeScript is an important step to take if you do not test every code path that you build.
Why I enjoy TypeScript every day
At the end of the day, I feel that using TypeScript makes me faster:
- intellisense is very convenient
- having automatic imports with tools like typescript-hero,
- being able to safely change a function signature and have compiler warnings about usages
- show-usages is wonderful too
Thoughts?
Software Engineer