TypeScript Explained: Why Developers Are Switching from Plain JavaScript
JavaScript runs the web. It’s in every browser, every web framework, and increasingly on servers through Node.js. But JavaScript has a well-known weakness: it lets you do things that obviously shouldn’t work, and only tells you about it when something crashes at runtime.
TypeScript was built to fix that. It’s now one of the most popular languages in professional software development, and understanding it is increasingly expected for any serious web or Node.js developer.
What TypeScript Is
TypeScript is JavaScript with a type system layered on top. It’s a superset: every valid JavaScript file is also valid TypeScript. You add TypeScript gradually — you don’t have to rewrite everything at once.
TypeScript code gets compiled to plain JavaScript before running. Browsers and Node.js don’t run TypeScript directly; the TypeScript compiler (tsc) strips out the type annotations and produces the JavaScript your runtime actually executes.
The key point: TypeScript only affects development time. At runtime, it’s just JavaScript. TypeScript’s value is entirely in the feedback it gives you while you’re writing code.
The Problem TypeScript Solves
Here’s a classic JavaScript footgun:
function greet(user) {
return `Hello, ${user.name}`;
}
greet(42); // runs without error, produces "Hello, undefined" JavaScript accepts this. You won’t find out something is wrong until the function runs in production and produces garbage output — or crashes trying to access a property on a number.
With TypeScript:
function greet(user: { name: string }) {
return `Hello, ${user.name}`;
}
greet(42); // Error: Argument of type 'number' is not assignable to parameter The error appears in your editor, before you save, before you run anything. The problem is caught immediately instead of in production.
How TypeScript Works
Type Annotations
You declare what types variables and function parameters should be:
let age: number = 25;
let name: string = "Alice";
let active: boolean = true; TypeScript also infers types when you don’t annotate:
let count = 0; // TypeScript infers: number
count = "hello"; // Error: Type 'string' is not assignable to type 'number' You don’t have to annotate everything — TypeScript figures out a lot from context.
Interfaces and Types
You can define the shape of objects:
interface User {
id: number;
name: string;
email: string;
role: "admin" | "editor" | "viewer";
}
function getUser(id: number): User {
// must return an object matching the User shape
} If your function returns something that doesn’t match User, TypeScript flags it immediately.
Union Types
Variables can accept multiple types:
function formatId(id: number | string) {
return id.toString();
} TypeScript tracks which type you’re working with inside conditionals:
function process(input: number | string) {
if (typeof input === "string") {
return input.toUpperCase(); // TypeScript knows it's a string here
}
return input * 2; // TypeScript knows it's a number here
} This is called type narrowing, and it’s one of TypeScript’s more useful features.
Generics
Generics let you write reusable code that works with any type while preserving type safety:
function firstItem<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = firstItem([1, 2, 3]); // TypeScript knows: number | undefined
const str = firstItem(["a", "b"]); // TypeScript knows: string | undefined You get the flexibility of dynamic code with the safety of specific types.
What TypeScript Catches
The practical payoff of TypeScript is catching errors that would otherwise hide until runtime:
Typos in property names:
const user = { firstName: "Alice", lastName: "Smith" };
console.log(user.firstname); // Error: Property 'firstname' does not exist — did you mean 'firstName'? Wrong function arguments:
function add(a: number, b: number) { return a + b; }
add(1, "2"); // Error: Argument of type 'string' is not assignable to 'number' Null/undefined access:
const user = getUser(id); // returns User | null
console.log(user.name); // Error: Object is possibly 'null'
// TypeScript forces you to check:
if (user) {
console.log(user.name); // safe
} Refactoring confidence: When you rename a function or change its signature, TypeScript immediately shows every call site that needs updating. Without types, you have to find them all manually and hope you caught everything.
TypeScript and Your Editor
TypeScript’s biggest quality-of-life improvement might be IDE integration. VS Code has TypeScript support built in — you get:
- Autocomplete that knows the exact properties and methods available on any object
- Inline error highlighting before you run anything
- Hover documentation that shows type signatures
- “Go to definition” that works accurately across your entire codebase
- Refactoring tools that update all references automatically
This level of editor support is largely impossible with plain JavaScript, where the editor can’t know what properties an object might have.
TypeScript vs JavaScript: When to Use Each
Use TypeScript for:
- Any project larger than a few files
- Projects with multiple contributors
- Long-lived codebases that will be maintained and extended
- Libraries and packages used by others
- Node.js backends
JavaScript without TypeScript is fine for:
- Small personal scripts
- Quick prototypes you’ll throw away
- Projects where setup overhead isn’t worth it
Most serious JavaScript projects — React apps, Angular apps (which requires TypeScript), large Node.js backends, open source libraries — use TypeScript by default.
Getting Started
TypeScript integrates cleanly into existing JavaScript projects.
Install TypeScript:
npm install --save-dev typescript
npx tsc --init # creates tsconfig.json Rename a .js file to .ts and start adding types incrementally. You don’t need to convert everything at once.
If you’re using a framework:
- React: Create React App and Vite both have TypeScript templates
- Next.js: TypeScript support is built in, just rename files to
.tsx - Node.js/Express: Add
@types/nodeand@types/expressfor type definitions
Learn as you go: TypeScript’s error messages are unusually readable. When you see one you don’t understand, it usually links directly to the TypeScript documentation or has enough context to search for.
TypeScript’s adoption among professional developers isn’t accidental. The upfront cost — learning the syntax, configuring the compiler — pays dividends quickly: fewer bugs in production, a faster feedback loop during development, and dramatically better editor support. If you’re writing JavaScript professionally and haven’t picked up TypeScript yet, it’s time.
Written by Marcus Thorne
Software analysis and cybersecurity tips
A former software engineer, Marcus transitioned into tech journalism to explain complex digital concepts in simple terms.
You Might Also Like

CI/CD Explained: How Modern Software Gets Tested and Deployed
CI/CD turned deploying software from a stressful manual process into something that happens dozens of times a day without drama. Here's how it works.

AI Coding Assistants Explained: What GitHub Copilot Actually Does
AI coding tools write code, suggest fixes, and explain functions. Here's how they actually work, what they're good at, and where they fall short.

Git for Beginners: Version Control Explained
Git is the most important tool in software development that nobody properly teaches. Here's how it actually works and the commands you need to know.
