TypeScript’s pitch is simple: catch the bugs a type system would catch, before your code ever runs, while still compiling down to plain JavaScript that runs anywhere JS already does. Here’s what actually changes in your day-to-day code.
Basic Type Annotations
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
calculateTotal(9.99, "2"); // Error caught at compile time, before you ever run it:
// Argument of type 'string' is not assignable to parameter of type 'number'
Interfaces: Shaping Your Data
interface User {
id: number;
name: string;
email: string;
isAdmin?: boolean; // optional property
}
function greetUser(user: User): string {
return <code>Hello, ${user.name}!</code>;
}
greetUser({ id: 1, name: "Alice", email: "alice@example.com" }); // valid
greetUser({ id: 1, name: "Alice" }); // Error: missing required property 'email'
Generics: Reusable, Still Type-Safe
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
const firstNumber = firstItem([1, 2, 3]); // inferred as number
const firstName = firstItem(["Alice", "Bob"]); // inferred as string
Adopting It Gradually
You don’t need to rewrite an existing JavaScript project from scratch — TypeScript accepts plain JS files, and you can migrate file by file, adding types incrementally. Even without full strictness enabled, the editor autocomplete and inline type errors alone catch a meaningful share of bugs before runtime.
npm install --save-dev typescript npx tsc --init # Rename .js files to .ts one at a time as you migrate