How I Started Writing TypeScript
The first time I tried writing TypeScript, it didn’t stick.
After two hours, my main takeaways were:
- This makes my code harder to write
- I could accomplish this with vanilla JS much faster
- Everything easy is hard again
Ultimately, I left with the impression that TypeScript was another tool I didn’t need.
Fast forward 12 months and my opinion has completely changed. TypeScript is the most valuable thing I’ve learned all year. If you’ve been on the fence about whether to embrace TypeScript, I’d encourage you to give it a try.
What is TypeScript?
Why do I need TypeScript?
Well… you don’t. But you might want it if:
- You frequently work with other engineers in a shared codebase.
- You’ve ever made a “small change” to a piece of code only to discover later that the change unintentionally broke other parts of the codebase – parts you didn’t think were related in any way.
- You don’t feel like you can make changes to your codebase with confidence. As a result, you frequently spend hours visually QAing your work to make sure nothing broke.
- Your project has a component-based architecture (React, Vue, etc) and you can never remember which components take which props.
- You’re willing to invest a little extra effort up front in exchange for enjoying a more pleasant, sane, and productive programming experience as your project grows.
Why static types?
Many human problems are the result miscommunication. One person expects another person to perform a task in a certain way and becomes frustrated when the task is not completed in accordance with their expectations. It’s unlikely that either party intends harm, but a lack of clearly defined and mutually agreed-upon expectations leads to unexpected results.
This same scenario happens in code all the time: a function requires specific data to perform correctly; everything crashes when its expectations are not met.
Static types largely solve this problem. When expectations are aligned with reality, writing code becomes a much more pleasant and predictable experience.
TypeScript in action
What does it look like? How does it work? Let’s dive into some code.
Say we have a vanilla JS function that logs a message announcing today’s lunch. It has one parameter called mainEntree:
It’s fairly obvious from reading the code above that the mainEntree parameter should be a string. But nothing is stopping us from calling logTodaysLunch with a number as the argument like this:
The code above would not cause any errors because it is technically valid. But it would result in a message that reads “Today’s lunch is 197”, which is not what we intended. Most people don’t like to eat numbers for lunch.
This is precisely the problem TypeScript and static types solve.
With TypeScript, we can assign mainEntree a type of string:
Which will result in this helpful error message if logTodaysLunch is called with a number:
Nice catch! TypeScript just caught a bug automatically.
But what if we try to call logTodaysLunch with a nonsensical string? Can we trick TypeScript?
No error. Hmm… not ideal. Cybertruck does not taste good either.
Luckily, TypeScript will allow us to create a custom type:
This time, TypeScript catches the error and provides a helpful message:
Now we know logTodaysLunch is expecting an argument that matches one of the values we defined in LunchType. It will only accept sandwich, soup, or salad. Another edge case eliminated!
TypeScript empowers many IDEs to provide contextual information that can help you be more productive. VSCode’s IntelliSense feels a lot like a superpower.
All of the examples above were easy to follow because we called logTodaysLunch in the same file immediately after it was defined. The reality is that this function could be imported from a helper file like this:
Without the function definition directly above to provide context, we no longer know what argument(s) to pass to logTodaysLunch. Normally, we’d have to track down the lunchHelpers file and read through everything.
Not with TypeScript. If you were to hover over logTodaysLunch in VSCode, you’d see the following IntelliSense tooltip:
We immediately know that logTodaysLunch takes one argument called mainEntree that has a type of LunchType. This contextual information is especially helpful for a new engineer who has never used the logTodaysLunch function before. Plus, we can proceed with confidence knowing TypeScript will catch any errors if an incorrect value is passed.
When to use TypeScript
For future projects, I plan to:
- Always use TypeScript to build anything that qualifies as an “app”. TypeScript is most helpful for complex projects.
- Evaluate everything else on a case-by-case basis. If I can get the job done with 20 lines of vanilla JS or jQuery, I see no reason to add additional complexity and install TypeScript.
Making the investment
The big questions to ask when learning a new technology are:
- Will the time investment required to learn this new tech pay off in terms of increased productivity, better code quality, or developer happiness?
- Will this new technology still be around in 5 to 10 years?
For TypeScript, the answer to both is a resounding YES.
Start writing TypeScript. Start writing code that scales.