let age: number = 21;
let name: string = "Ravi";
let isStudent: boolean = true;
function add(a: number, b: number): number {
return a + b;
}
add(5, "10"); // โ TypeScript catches this at compile time - can't add a number and a stringTypeScript's core value proposition, right here: the mismatched-type call to add() is caught immediately by your editor and the compiler, long before it would have become a confusing runtime bug in plain JavaScript.
interface Student {
name: string;
age: number;
email?: string; // the ? marks this property as optional
}
function greet(student: Student): string {
return `Hello, ${student.name}`;
}
greet({ name: "Neha", age: 22 }); // โ
valid - email is optional
greet({ name: "Raj" }); // โ error - age is requiredAn interface describes the exact shape an object must have. TypeScript checks every object passed where a Student is expected, catching missing or mistyped fields immediately โ exactly the kind of prop-shape bug that plain React/JavaScript can only catch at runtime, if at all.
type Status = "loading" | "success" | "error";
function getMessage(status: Status): string {
if (status === "loading") return "Please wait...";
if (status === "error") return "Something went wrong.";
return "Done!";
}
function printLength(value: string | number) {
if (typeof value === "string") {
console.log(value.length); // TypeScript now KNOWS this is a string here
} else {
console.log(value.toFixed(2)); // and knows this branch is a number
}
}A union type (string | number) means a value could be either type. Type narrowing โ checking with typeof or comparing against specific values โ lets TypeScript automatically figure out exactly which type applies inside each branch, unlocking the correct methods for that specific type.
function getFirstItem<T>(items: T[]): T {
return items[0];
}
const firstNumber = getFirstItem([1, 2, 3]); // TypeScript infers T is number
const firstName = getFirstItem(["Amit", "Neha"]); // TypeScript infers T is stringGenerics let a function work correctly with any type while still preserving full type safety โ getFirstItem works on an array of any type, and TypeScript always knows exactly which type it returned for that specific call, without needing to write a separate version per type.
Typing something as any tells TypeScript to stop checking it entirely โ which defeats the entire purpose of using TypeScript in the first place. It's tempting as a quick fix when a type error is confusing, but reaching for any repeatedly means you're paying TypeScript's complexity cost without getting its safety benefits in return.
Define an interface for a Product with name (string), price (number), and an optional description field, then write a function that formats it as a display string.
interface Product {
name: string;
price: number;
description?: string;
}
function formatProduct(product: Product): string {
return `${product.name} - $${product.price}`;
}
console.log(formatProduct({ name: "Mouse", price: 799 }));
Q Do I need to rewrite my whole React app in TypeScript at once?
No โ TypeScript can be adopted incrementally, file by file, in most project setups. Many teams start by adding it to new files while leaving existing .jsx files as-is, migrating gradually over time.
Q What's the difference between 'interface' and 'type' for describing object shapes?
For basic object shapes, they're nearly interchangeable, and it's largely a team style preference. 'interface' has some extra features specifically for object-oriented patterns (like being extended), while 'type' is slightly more flexible for things like union types.