TypeScript in 15 Minutes for JavaScript Developers Who Hate TypeScript
Source: Dev.to

It’s JavaScript with intent, discipline, and receipts.
At its core, TypeScript is just JavaScript plus types and generics — nothing more, nothing magical. It doesn’t add new runtime behavior; it simply makes sure you don’t lie to yourself (or your teammates) while writing code.
If you already know JavaScript, this is the fastest way to understand what actually matters in TypeScript.
JavaScript vs. TypeScript: The Truth About Types
TypeScript does NOT introduce new primitive data types.
Everything you already know still exists:
stringnumberbooleannullundefinedsymbolbigint
TypeScript’s job is not invention — it’s enforcement.
- JavaScript: “You’ll figure it out at runtime.”
- TypeScript: “Prove it before you run it.”
Methods Are the Same — Safety Is Not
All your familiar methods still exist:
- Strings →
concat,slice,charAt - Arrays →
map,filter,reduce,find
The difference is that TypeScript knows what you’re allowed to call.
let nums: number[] = [1, 2, 3];
nums.map(n => n * 2); // ✅ OK
nums.map(n => n.toUpperCase()); // ❌ Error – caught at compile time
JavaScript would let the second line fail at runtime; TypeScript stops it at compile time. That’s the entire value proposition.
Type Annotations vs. Type Inference
You can explicitly annotate:
let name: string = "Ram";
But TypeScript is smarter than that:
let name = "Ram"; // inferred as `string`
TypeScript tracks types automatically. This is called type inference, and it’s why declaring variables in one place and mutating them elsewhere is usually a bad idea.
The any Trap (Don’t Do This)
A lot of people use any to “escape” TypeScript, which defeats the purpose.
let value: any = 10;
value.toUpperCase(); // ✅ TS allows it, but runtime explodes
That’s why noImplicitAny exists in tsconfig.json. If you’re using any everywhere, you’re essentially writing plain JavaScript with extra steps.
Functions: Parameters AND Returns Matter
TypeScript isn’t just about inputs — outputs matter too.
function addTwo(num: number): number {
return num + 2;
}
Without the return type, the following would still compile, but it would be a bug:
function addTwo(num: number) {
return "hello"; // ❌ Type error if return type is declared
}
TypeScript lets you lock both sides of the contract.
Special Return Types
void→ function performs side effects onlynever→ function never returns (throws or crashes)
function handleError(msg: string): void {
console.log(msg);
}
function crash(msg: string): never {
throw new Error(msg);
}
Why Return Types Matter in Teams
A well‑typed function tells a story without reading its body:
function getCourse(): { title: string; price: number } {
return { title: "TypeScript Mastery", price: 499 };
}
Anyone can instantly see:
- What it returns
- The exact structure
- What’s mandatory
That’s not just syntax; it’s team communication.
Type Aliases: Naming Shapes
Type aliases let you give intent a name.
type User = {
name: string;
email: string;
isActive: boolean;
};
JavaScript says “trust me.”
TypeScript says “prove it.”
readonly, Optional, and Union Types
readonly
readonly _id: string;
You can read it, but you can’t mutate it.
Optional Properties
creditCard?: number;
The property might exist or not; TypeScript forces you to check.
Union Types
let id: number | string;
Used heavily in:
- Role‑Based Access Control (RBAC)
- API responses
- Conditional flows
Tuples: Controlled Chaos
Tuples are ordered, typed arrays:
let user: [string, number, boolean];
- They exist only in TypeScript – the compiled JavaScript doesn’t care.
push()still works (but use it sparingly).- Use them only when the order truly matters.
Enums: Named Constants
const enum SeatChoice {
aisle = 10,
middle,
window
}
- Readable and predictable.
- Zero runtime ambiguity because the enum is inlined at compile time.
Interfaces vs. Types (Short Version)
Interfaces
- Extendable.
- Work beautifully with classes – enforce OOP contracts.
interface IUser {
email: string;
startTrial(): string;
}
- Interfaces can be reopened (declaration merging).
- Types cannot be reopened.
Types
- Useful for unions, intersections, and primitive aliases.
- Not merge‑able, but great for one‑off shapes.
Classes, Constructors, and Access Modifiers
TypeScript makes OOP less painful:
class User {
constructor(
public email: string,
public name: string,
private userId: string
) {}
}
Access Modifiers
| Modifier | Visibility |
|---|---|
public | Anywhere |
private | Inside the class only |
protected | Inside the class and its subclasses |
These modifiers help you stop “access chaos” in real systems.
Interfaces + Classes = Structural Integrity
Interface (shape)
interface TakePhoto {
cameraMode: string;
filter: string;
}
Class (behavior)
class Camera implements TakePhoto {
cameraMode = "auto";
filter = "none";
snap() { /* … */ }
}
Interfaces define what must exist; classes provide the implementation.
This pattern scales incredibly well in backend (and frontend) systems.
Abstract Classes: Intent Without Instantiation
abstract class TakePhoto {
abstract getSepia(): void;
}
- Cannot be instantiated directly.
- Sub‑classes must implement the abstract members, guaranteeing required behavior.
Generics: The Real Power Move
Generics let you write logic once – safely:
function identity<T>(val: T): T {
return val;
}
Common places where generics shine:
- API client wrappers
- Repository patterns
- Response models
They’re not an OOP replacement; they’re an evolution of type safety.
Type Narrowing: Runtime Safety
TypeScript never “guesses” – you narrow types explicitly with:
typeofchecksinstanceofchecks- The
inoperator
These techniques keep the compiler happy while ensuring correct runtime behavior without reflection.
Discriminated Unions (Cleanest Pattern)
interface CreditCard {
paymentType: "card";
cardNumber: string;
}
interface PayPal {
paymentType: "paypal";
email: string;
}
type PaymentMethod = CreditCard | PayPal;
- A single discriminant field (
paymentType) gives zero ambiguity. - Perfect for
switchstatements or exhaustiveifchecks.
Conclusion
- TypeScript doesn’t slow you down – unclear code does.
- It makes ambiguity illegal, forcing you to write explicit, maintainable, and type‑safe code.