What Is TypeScript and Why Use It?
Understand what TypeScript is, why it matters, and how it helps us write better JavaScript.
Let’s start with the obvious: JavaScript is everywhere, and it’s powerful. But it’s also error-prone, hard to scale, and too permissive for its good. This is where TypeScript comes in.
TypeScript is a typed superset of JavaScript that compiles down to plain JavaScript. That means every JS file is already a valid TS file (syntactically). It layers a powerful, statically typed system on top of the language we already use every day. It’s designed to help us write safer code, catch bugs earlier, and build better tools and workflows.
Let’s unpack what makes TypeScript such a game-changer for modern development.
What does TypeScript add on top of JavaScript?
At its core, TypeScript doesn’t replace JavaScript—it extends it. Anything we can do in JS, we can do in TS. But with TypeScript, we get additional features like:
Static type checking
Modern ECMAScript features, even before browsers support them
Rich development tooling (IntelliSense, auto-complete, refactors)
Here’s a simple JavaScript function:
function greet(name) {return "Hello, " + name.toUpperCase();}console.log(greet("Mark"));
And here’s the equivalent TypeScript version:
function greet(name: string): string {return "Hello, " + name.toUpperCase();}console.log(greet("Mark"));
In the TS version, we explicitly state that name
is a string
, and the function returns a string
. This lets TypeScript catch incorrect usage at compile time, like if we tried to call greet(42)
.
Do it yourself: Try calling both versions with
greet(42)
instead ofgreet("Mark")
and see what happens.
TypeScript compiles to JavaScript
TypeScript doesn’t run in the browser or Node directly. It compiles to standard JavaScript, which means we can run our code anywhere JavaScript runs.
Let’s walk through that process with a simple example. In the interactive environment below, you can write TypeScript, compile it, and run the resulting JavaScript. Click “Run” below to open a terminal and follow these steps:
-
Compile the TypeScript code:
tsc index.ts
Note:
tsc
is the TypeScript compiler. It reads your.ts
files and emits plain JavaScript. -
View the generated JavaScript code:
cat index.js
-
Run the JavaScript file:
node index.js
function isEven(n: number): boolean { return n % 2 === 0; } console.log(isEven(32));
The type annotations (n: number
and : boolean
) only exist during development—they’re removed when the code compiles.
We’ve seen how TypeScript compiles and what it strips out. But what do those type annotations actually give us? Let’s talk about what makes static types such a big deal.
Why do static types matter?
Static typing means that TypeScript checks the types of our variables, parameters, and return values at compile time—before the code runs. It ensures that values match their intended shape, helping us catch mismatches and bugs early, before they ever hit production.
With types, we shift error detection left—from runtime to compile time. That means:
Fewer surprises during execution.
Easier refactors.
Better auto-complete and editor support.
Take this buggy JavaScript:
function double(x) {return x + x;}console.log(double("3")); // logs "33" — oops
Let's rewrite this logic in TypeScript:
function double(x: number): number {return x + x;}console.log(double("3")); // Compile-time error
TypeScript prevents us from calling double
with a string. That’s not just a warning—that’s a hard stop before our code runs.
Note: Even if your code has type errors, TypeScript will still emit the compiled JavaScript by default. Unless we explicitly tell it to stop, TypeScript won’t block execution. That’s what makes TypeScript so approachable—you can adopt it incrementally and fix issues on your terms.
JavaScript vs. TypeScript: Catching bugs early
TypeScript shines where JavaScript fails silently. Here’s a classic runtime failure:
function getUser(id) {return { id, name: "Alice" };}console.log(getUser(1).email.toLowerCase()); // Cannot read property 'toLowerCase' of undefined
Here’s how TypeScript handles it:
function getUser(id: number): { id: number; name: string } {return { id, name: "Alice" };}console.log(getUser(1).email.toLowerCase()); // Error: Property 'email' does not exist
TypeScript immediately tells us there’s no email
field. We fix it before the bug ships.
TypeScript’s type system catches a lot of type-related bugs—but not all of them. It’s designed to flag type issues at compile time, but certain patterns (like dynamic input or incomplete typings) can still slip through. Think of it as a powerful safety net, not a guarantee.
TypeScript improves safety, collaboration, and tooling
Let’s be blunt: JavaScript doesn’t scale well without discipline. On big teams or long-lived codebases, we need guardrails. TypeScript gives us:
Safety: Catch bugs from incorrect types, missing fields, or null values—before they explode at runtime.
Clarity: Types act as living documentation, making it easier to read, refactor, and review code across teams.
Tooling: Auto-complete, inline hints, refactors, and smarter navigation—all powered by the type system.
It’s not just about correctness—it’s about velocity. With TypeScript, we build faster, debug less, and scale with confidence.
Key takeaways:
TypeScript is a typed superset of JavaScript—it adds static types without taking anything away.
It compiles down to regular JavaScript, so it works everywhere JS does.
Static typing catches bugs early, improves safety, and supercharges tooling.
Bugs that would silently pass in JS often get caught immediately in TS.
TypeScript helps teams write clearer, more maintainable code with greater clarity around how how it’s written, used, and understood.