Effective Typescript | A Non-Technical Guide
Published on Sep 13, 2020
There is a lot of hype around Typescript these days, and for good reason. It finds the perfect balance between the dynamic nature of Javascript and the tried-and-tested static nature of other languages.
Since giving it a try in my first Angular projects a few years ago, I have absolutely fallen in love with Typescript. So much so that I will often refuse to pick up a framework or template that doesn’t make use of it. I know this might sound a bit extreme, but hear me out.
Why Use Typescript
I’ll keep this short and sweet, as most of these points have been explained ad nauseam in other articles.
Fewer Bugs: By adding type definitions to your variables, classes, and functions, you provide your IDE with a way to give you feedback before runtime. This means you can catch errors during compilation, or even better, while you are coding.
Improved Autocomplete: Since your IDE now knows the types of most objects, it will only suggest relevant properties and methods for code completion. Visual Studio Code, Intellisense, and Typescript are all Microsoft’s babies, so when used together, the developer experience is truly fantastic, even on par with fully static languages like Java or C-based languages.
Self-Documenting Code: I generally hold the opinion that the best comments and documentation are no comments and no documentation at all. If your code is simple, clear, and concise, it effectively serves as documentation in itself. Type definitions, together with improved autocomplete, lend themselves to self-documenting code.
Low Barrier to Entry: Essentially, if you know Javascript, you can get started with Typescript with virtually no hassle. Typescript is a superset of Javascript, and it compiles back down to pure Javascript before being shipped to the browser.
The main takeaway is that at the cost of a little extra complexity, Typescript will drastically improve your development experience.
Effective Typescript
Have you ever been thrown into an obscure Javascript codebase and asked to add a new feature or refactor an existing one with a short deadline looming ahead? Everything is unfamiliar and overwhelming. The fear of the unknown is the greatest fear of all. Well, that may be a bit overdramatic, but I’m sure you get the point.
Having to do this in a static codebase, such as a C# or Kotlin project, would still be tough but a drastically better experience. Why? Because most of the time, we can trust our IDE to tell us where any changes may have unexpected consequences in other parts of our codebase. This isn’t necessarily the case with a Javascript project, and not always with a Typescript project either.
So, how can we fix this?
Here is my main approach when it comes to writing effective code:
All consequences of a code change should immediately be made visible.
In other words, I am constantly thinking something along the lines of: If someone were to come back to this code in a few months and had to make changes, would their IDE or compiler immediately show them where any unintended modifications would need to be made elsewhere? Whether it’s within the same file or set of files, or potentially across boundaries if you have modified a shared database object, for example.
Static languages heavily enforce this through the use of statically typed objects, such as a Data Access Object (DAO) for anything that comes from a database. Any change to the DAO will immediately reflect throughout the codebase.
Static languages also discourage any dynamic code that can’t be checked during compilation. Reflection is one such example where things can slip through the cracks, which is why it is used in very few circumstances.
Okay, enough about the joys of static code. Don’t even get me started on the headaches static languages can be, too. Java, I’m talking about you with all your annoying boilerplate. The real question is, how can we get this level of reliability and trust from Typescript?
Type Everything
This one is relatively straightforward. See any code with the word any
? Or any unknown
types lying around? Change them to be the real type.
Another helpful tip is to get your linter to assist you here. The no-explicit-any
ts/eslint rule is particularly useful. It prevents variables with an any
type that is not explicitly provided.
In some cases, any
(or preferably unknown
) is necessary, but providing a comment above the any
explaining why it is needed can often help alleviate potential confusion for future developers.
Use Enums or Type Literals
A common use case is trying to limit an option to only certain values. For example, consider HTML input types such as text
, number
, button
, checkbox
, etc. Although not optimal, we may have conditional logic in multiple places depending on this value. Now, picture adding a new input type. It becomes incredibly easy to forget to add a new case to your switch statements. We can make this a lot more maintainable by using Enums or Type Literals. Doing so allows your compiler to automatically detect if a new case needs to be added to a switch statement.
// Using an Enum
enum Colors = { Red, Blue, Green };
// Using a Type Literal
type Colors = 'Red' | 'Blue' | 'Green';
Statically Typed Templates
Now, here things can get a bit tricky. To try to achieve complete type checking throughout our codebase, we somehow need to ensure our templates are type-checked. However, HTML does not support static type checking out of the box.
Luckily, most modern frameworks have found a way around this, be it Angular with its Language Service or React with its TSX support. Vue has partial support with the Vetur extension, or you could always go the TSX route with Vue, too. Template type checking is a hot topic in Vue right now, so maybe something will spring out of the woodwork soon.
All in all, with a few minor changes and a shift in thinking, we can come close to the reliability we would find in most static languages. This is the trick to effective Typescript.
Conclusion
Typescript is fantastic. It can keep your clients happy by limiting the number of bugs you ship to production, keep your fellow developers happy since most of your code ends up documenting itself, and make you happy because you can spend more time writing features and less time fixing unexpected issues.
Learn the fundamentals of effective Typescript thinking, and you’ll be reaping the rewards in no time.
Hope you enjoyed the read and learned something while you were at it. Until next time ✌️