DEV Community

Cover image for A TypeScript Journey: When Type Safety Feels Like a Safety Harness… and Sometimes a 10 kg Stone on Your Feet
Gaurav Nadkarni
Gaurav Nadkarni

Posted on • Originally published at Medium

A TypeScript Journey: When Type Safety Feels Like a Safety Harness… and Sometimes a 10 kg Stone on Your Feet

Introduction

When I first started writing code, I lived in the world of Java. It was a place where types were everywhere, like street signs you couldn’t ignore. If you tried to drive your program the wrong way, the compiler would pull you over before you even left the garage. It was safe, predictable, and sometimes a little suffocating.

Then I met JavaScript. Suddenly, I was free. No one asked me to declare the type of a variable, no one complained if I changed my mind halfway through a function, and I could write something messy and watch it still run. It felt liberating until the first time I spent an hour debugging only to find that I had misspelled a property name.

That’s when TypeScript walked in. It promised the best of both worlds: the freedom of JavaScript with just enough guardrails to stop me from repeatedly shooting myself in the foot. And to be fair, it often delivered. But along the way, I also learned that type safety can feel like wearing a sturdy safety harness… or like trying to run a marathon with a 10 kg stone tied to your feet.

This article is a reflection on that journey: the wins, the frustrations, the times TypeScript saved me, and the times it got in the way. If you’ve ever wrestled with types, cursed at the compiler, or wondered if you should just stick to plain JavaScript, I think you’ll relate.

My Background Coming from Java and Its Static Types

I started out in Java, where everything had to be neatly defined before you could even think about running your program. You couldn’t just say, “Here’s a variable, I’ll decide what it is later.” No, you had to declare its type, its purpose, and practically its hopes and dreams before the compiler would even let you compile.

At first, I found comfort in that rigidity. The compiler was like a strict but caring teacher. It wouldn’t let you turn in sloppy work. If I tried to pass a string where an integer was expected, I’d be scolded immediately, long before my code could cause trouble in production. There was a kind of safety in knowing the rules of the game were always enforced.

But over time, I also realized that Java’s strong typing could feel like bureaucracy. Sometimes I just wanted to test a simple idea, but I had to fill out all the forms: classes, interfaces and boilerplate before I could even write “Hello, World.” Still, those years shaped how I think about code: predictable, well-structured, and with the comforting knowledge that the compiler had my back.

So when I later wandered into the wild west of JavaScript, you can imagine the shock.

JavaScript and the Need for Typing

Switching from Java to JavaScript felt like moving from a well-ordered office into a lively street market. In JavaScript, you could pick up anything, call it whatever you wanted, and no one would stop you. Want to treat a number like a string? Go ahead. Accidentally return an object when you promised an array? No problem… JavaScript will just smile and keep running. Compared to Java’s form-filling discipline, this was a revelation.

The joy was real. I could prototype faster than ever before. I didn’t have to spend half an hour explaining to the compiler that, yes, this variable really was supposed to be a string. JavaScript trusted me, and in those early days, that trust felt empowering.

My joy was unmeasurable but little did I know that freedom came with hidden costs. The first time I passed a function expecting an object a null value, everything exploded at runtime. The famous “undefined is not a function” error became my constant companion, and debugging started to feel like detective work in a crime scene I accidentally created.

The bigger the codebase got, the harder it became to manage. Without clear types, I’d forget what shape an object was supposed to have or what a function was supposed to return. Reading my own code after a few months felt like reading someone else’s messy notes, vague hints, no guarantees, and a lot of room for misinterpretation.

The more I built, the more I realized that JavaScript’s charm could become chaos without some structure. And that’s when I started to think: maybe what I needed wasn’t a return to Java’s rigidity, but a middle ground, something that let me keep the joy of JavaScript while avoiding the worst of its pitfalls. That’s where TypeScript entered the picture.

When I Found Type Safety to Be a Potent Solution

When I first started using TypeScript, it reminded me a little of Java but without all the extra ceremony. Suddenly, my editor was more than just a place to write code. It actually helped me. It showed me what arguments a function expected, what type of value I would get back, and it warned me when I tried to use something the wrong way.

The best part was how it caught small mistakes early. If I misspelled a property name or passed a number where a string was expected, TypeScript stopped me right away. These were the kind of mistakes that would have taken me hours to notice in plain JavaScript.

I also liked how types worked as documentation. Instead of guessing what an object should look like or digging through old code, I could see it right in front of me. That made it easier for me to come back to my own code later, and it made teamwork smoother too. Everyone could understand the shape of data or the purpose of a function without asking around.

For the first time in JavaScript, I felt a little safer. TypeScript didn’t make me a better programmer overnight, but it did save me from a lot of silly bugs and misunderstandings.

Why TypeScript Felt Potent:

  • Caught mistakes early: It prevented bugs by warning about wrong types, misspelled properties, or incorrect function usage before running the code.
  • Made code easier to understand: Types acted as self-documenting guides, showing exactly what objects and functions were supposed to look like.
  • Improved coding efficiency: IDE features like autocomplete and IntelliSense worked better with types, helping you write code faster and with fewer errors.

Why Types Sometimes Felt Like Tying a 10 kg Stone to Your Feet and Running a Marathon

As much as I appreciated what TypeScript brought to the table, it wasn’t all sunshine and smooth sailing. Sometimes, using types felt heavy, like I had an extra 10 kg strapped to my legs while trying to run.

Simple things could suddenly take longer than expected. Want to quickly pass an object to a function? If the type definitions weren’t perfectly aligned, the compiler would complain. Trying to satisfy it could take more time than writing the actual logic. Generics, union types, and complex type intersections were powerful, sure but they could also make my head spin.

There were moments when I found myself fighting the type system rather than using it. A function that worked perfectly fine in JavaScript suddenly threw red squiggly lines because the type checker didn’t like something subtle I did. I’d spend minutes or sometimes hours tweaking type definitions instead of focusing on the real problem.

It became clear that while types catch many mistakes, they also come with a cost. There’s a balance to strike between type safety and developer speed. Too strict, and you feel weighed down; too loose, and you risk slipping on a bug.

Even so, despite the occasional frustration, I kept coming back to TypeScript because for all the extra work, it still prevented more headaches than it created.

Why TypeScript Can Feel Heavy:

  • Extra time for simple tasks: Even small changes can require updating type definitions, slowing down development.
  • Complexity with advanced types: Generics, union types, and intersections can be powerful but sometimes confusing or overcomplicated.
  • Fighting the compiler: At times, the type system seems to block working code, making you spend more time satisfying the compiler than solving the actual problem.

When Type Safety Didn’t Really Work

Even with all the benefits TypeScript brought, there were times when it couldn’t save me. Type safety can prevent certain mistakes, but it doesn’t make your logic perfect. I’ve had functions that passed all type checks but still produced wrong results because the underlying algorithm was flawed. The compiler happily approved my mistakes, leaving me scratching my head at runtime.

Another frustration came from third-party libraries. Not every library has perfect type definitions. Sometimes the types were missing, incomplete, or outright wrong. That meant I either had to write my own types, ignore errors, or risk subtle bugs sneaking through none of which were particularly fun.

Dynamic data like API responses or user input can also bypass the safety net. You can type everything perfectly on paper, but the real world rarely behaves as expected. JSON structures can change, fields can be missing, and suddenly the carefully typed code crashes anyway.

Type inference, while helpful, isn’t always smart enough. Sometimes TypeScript guesses a type that doesn’t match reality, leading to confusing errors that are tricky to debug. And optional or union types, while designed for flexibility, can add cognitive overhead checking for every possible case can be tedious.

Finally, overconfidence is a hidden danger. Passing the compiler gives a false sense of security. I’ve found myself thinking, “If it compiles, it must be correct” only to realize later that runtime bugs were still lurking.

In short, TypeScript is powerful, but it’s not a silver bullet. It helps a lot, but careful thinking, thorough testing, and realistic expectations are still essential.

When I Choose JavaScript Over TypeScript

Even after all my experiences with TypeScript, there are definitely times when I still reach for plain JavaScript. Sometimes, the speed and simplicity of JS just make more sense.

For quick prototypes or one-off scripts, the overhead of setting up types can feel unnecessary. If I just want to test an idea, hack together a small tool, or experiment with a library, TypeScript can slow me down more than it helps. JavaScript lets me move fast, make changes on the fly, and see results immediately.

There are also situations where the project is short-lived or the code won’t be maintained long-term. Spending extra time defining types for a small script or a hacky solution doesn’t make sense. In these cases, the flexibility and minimal setup of JavaScript outweigh the safety net TypeScript provides.

Finally, working solo sometimes means I know my own code well enough that type safety feels redundant. I can read my code quickly, keep track of variable shapes, and spot mistakes without the compiler holding my hand. TypeScript is amazing, but it’s not always necessary when the context doesn’t call for it.

In short, I reach for JavaScript when speed, simplicity, and flexibility matter more than strict safety.

When I Choose TypeScript

Even though there are times I prefer plain JavaScript, there are plenty of situations where TypeScript is my go-to. The main factor is usually scale. When a project is large or expected to last a long time, the safety and structure that TypeScript provides become invaluable.

TypeScript shines in team projects. Types act like a shared language that reduces confusion and miscommunication. When someone else writes a function or module, I can understand exactly what inputs it expects and what outputs it provides, without needing to read through pages of code or ask too many questions.

I also choose TypeScript when working with APIs or external data sources. Having explicit types helps catch unexpected changes or missing fields in responses, which can save hours of debugging later.

And then there’s maintainability. Returning to code after weeks or months is always easier with TypeScript. Types serve as reminders of how things are structured, making it simpler to add features or refactor without breaking unrelated parts of the code.

In short, TypeScript becomes my tool of choice whenever clarity, reliability, and collaboration matter more than raw speed. It’s not just about preventing bugs, it’s about building confidence in the code that I and others will rely on.

My Takeaway

TypeScript has been a fascinating journey for me. Coming from Java, I was used to strict types and compile-time safety, and JavaScript initially felt like a breath of fresh air. That freedom was exhilarating but it came with hidden costs, from runtime errors to messy, hard-to-maintain code.

TypeScript offered a middle ground. It caught many of the mistakes that would have haunted me in plain JavaScript, improved readability, and made teamwork much smoother. At the same time, it’s not without friction. Sometimes the type system feels heavy, overly strict, or just plain confusing. And of course, it can’t protect you from logic errors or unpredictable runtime data.

For me, the choice between JavaScript and TypeScript is all about context. I reach for JavaScript when speed, flexibility, or small-scale projects matter. I choose TypeScript when clarity, maintainability, and collaboration are priorities.

At the end of the day, types are a tool, not a guarantee. They guide you, catch mistakes early, and save time but they don’t replace careful thinking, testing, or judgment. And yes, sometimes they feel like a little extra weight but a safer, more confident weight.

Thank you for reading! If you enjoyed this article or have your own experiences with JavaScript and TypeScript, I’d love to hear from you! Share your thoughts in the comments, or reach out to me on X (@gauravnadkarni) or via email (nadkarnigaurav@gmail.com).

Top comments (0)