TypeScript for JavaScript Developers: A Practical Introduction
A no-fluff introduction to TypeScript for JavaScript developers — what it adds, what it costs, and how to write your first typed code in under an hour.
You write JavaScript and someone on your team (or a job listing) keeps mentioning TypeScript. You know it involves types. You are not sure whether it is worth the learning curve or just adds friction to something that already works.
This guide answers the practical questions: what TypeScript actually does, what it does not do, and how to start using it in a real project without rewriting everything.
What TypeScript Is and Is Not
TypeScript is JavaScript with a type layer on top. Every valid JavaScript file is a valid TypeScript file. TypeScript compiles to JavaScript — the types are erased completely before execution. At runtime, your code is plain JavaScript.
What TypeScript adds is a static analysis step that runs before your code executes. It reads your code, infers the types of values, and checks that you are using them consistently. When it finds a problem, it reports an error at compile time — before a user hits the bug in production.
TypeScript does not:
- Make your code run faster
- Validate data at runtime (types are compile-time only)
- Eliminate the need for tests
- Prevent every bug — only the class of bugs that come from wrong types
It does, in practice:
- Catch undefined variable access, property typos, and wrong argument types before you run the code
- Make your IDE significantly more useful (autocomplete, go-to-definition, inline errors)
- Serve as lightweight documentation — function signatures tell you what the function expects and returns
- Make refactoring less risky — rename a function and TypeScript finds every call site
Writing Your First TypeScript
You likely already have Node installed. Add TypeScript to a project:
npm install --save-dev typescript
npx tsc --inittsc --init creates a default tsconfig.json. For now, leave it as-is.
Create a file src/greet.ts:
function greet(name: string): string {
return `Hello, ${name}`;
}
console.log(greet("Alice"));
console.log(greet(42)); // Error: Argument of type 'number' is not assignable to parameter of type 'string'Run npx tsc and the compiler reports the error on greet(42) before the code runs. That is the whole value proposition in one example.
Basic Types
TypeScript includes primitive types that map directly to JavaScript runtime values:
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let nothing: null = null;
let missing: undefined = undefined;You do not need to write the type annotation on every variable. TypeScript infers the type from the value:
let name = "Alice"; // TypeScript infers: string
let age = 30; // TypeScript infers: numberAnnotate when inference cannot work — function parameters, for instance:
function add(a: number, b: number): number {
return a + b;
}Object Types and Interfaces
interface User {
id: string;
email: string;
role: "admin" | "member";
createdAt?: Date; // optional — can be undefined
}
function formatUser(user: User): string {
return `${user.email} (${user.role})`;
}The interface defines the shape. TypeScript checks that objects passed to formatUser have at least the required fields. The ? on createdAt means the property is optional.
Arrays and Union Types
const ids: string[] = ["abc", "def"];
const mixed: (string | number)[] = ["abc", 1, "def", 2];
// Union type: a value can be one of several types
type Status = "pending" | "active" | "cancelled";
let orderStatus: Status = "pending";
orderStatus = "shipped"; // Error: Type '"shipped"' is not assignable to type 'Status'Union types with string literals (sometimes called string enums or discriminated unions) are one of TypeScript's most practical features. They constrain values to a known set and TypeScript catches typos and invalid assignments.
The Learning Curve Is Real but Short
For JavaScript developers, the main adjustment period is:
Learning where to put types. The rule of thumb: annotate function parameters and return types. Let inference handle everything else.
Getting comfortable with null and undefined errors. With strictNullChecks on, TypeScript will tell you that a value might be undefined when you try to use it. This is correct — it means there is a real bug risk. Add a check, a default value, or a guard.
Understanding any. If you write let x: any, TypeScript stops checking x. It is the escape hatch that defeats the type system. Use it sparingly and only when necessary, usually at the edges where you are integrating with an untyped third-party library.
Most JavaScript developers are productive with TypeScript within a few days. The IDE experience alone (real autocomplete, inline errors, instant documentation) tends to win people over quickly.
What to Do Next
Once you are writing basic TypeScript comfortably:
- Enable
strict: truein your tsconfig and work through the errors - Add
noUncheckedIndexedAccess: true— it catches a common class of crash - Start typing your API response shapes and use a validation library at the boundary
If your team is starting a new product and wants TypeScript set up correctly from day one — config, patterns, and all — Clixo can get you there without the trial-and-error.