TypeScript Programming Language Guide — Typed JavaScript for Scalable Apps
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript, adding static type checking for catching errors at compile time rather than runtime.
What You’ll Learn
- Types, interfaces, and type annotations
- Generics for reusable, type-safe code
- Enums and type narrowing
- Utility types for common transformations
- tsconfig and compiling to JavaScript
Why It Matters
TypeScript catches bugs before they reach production. Doda Browser’s frontend uses TypeScript to prevent the “undefined is not a function” errors that plague large JavaScript codebases. TypeScript provides documentation through types — any developer can understand a function’s contract by reading its signature. Major frameworks like Angular, Next.js, and Vue all recommend TypeScript. It’s the standard for professional JavaScript development at scale.
Learning Path
flowchart LR
A[TypeScript Basics<br/>You are here] --> B[Types & Interfaces]
B --> C[Generics & Enums]
C --> D[Type Narrowing]
D --> E[Build a Typed API Client]
Setting Up TypeScript
Install TypeScript via npm and compile to JavaScript.
npm install -g typescript// greet.ts
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("TypeScript")); // Hello, TypeScript!
tsc greet.ts
node greet.js
# Hello, TypeScript!Basic Types and Annotations
TypeScript extends JavaScript with static types.
// Primitive types
let name: string = "Alice";
let age: number = 30;
let isActive: boolean = true;
let data: any = "can be anything"; // avoid when possible
// Arrays
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];
// Tuples
let pair: [string, number] = ["Alice", 30];
// Union types
let id: string | number = "abc123";
id = 456; // OK
// Type inference — TypeScript infers types automatically
let message = "Hello"; // inferred as string
Interfaces
Interfaces define the shape of objects.
interface User {
id: number;
name: string;
email: string;
age?: number; // optional property
readonly createdAt: Date; // cannot be changed after initialization
}
function createUser(name: string, email: string): User {
return {
id: Math.floor(Math.random() * 1000),
name,
email,
createdAt: new Date()
};
}
function displayUser(user: User): void {
console.log(`${user.name} (${user.email})`);
if (user.age) {
console.log(`Age: ${user.age}`);
}
}
const alice = createUser("Alice", "alice@example.com");
displayUser(alice);
// Alice (alice@example.com)
Generics
Generics create components that work with any type while preserving type safety.
// Generic function
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
console.log(firstElement([1, 2, 3])); // 1 (type: number)
console.log(firstElement(["a", "b"])); // a (type: string)
// Generic interface
interface Repository<T> {
getById(id: number): T | undefined;
getAll(): T[];
create(item: T): void;
delete(id: number): void;
}
class UserRepository implements Repository<User> {
private users: User[] = [];
getById(id: number): User | undefined {
return this.users.find(u => u.id === id);
}
getAll(): User[] {
return [...this.users];
}
create(user: User): void {
this.users.push(user);
}
delete(id: number): void {
this.users = this.users.filter(u => u.id !== id);
}
}Enums and Type Narrowing
Enums define named constants. Type narrowing refines types within conditional blocks.
enum Direction {
North = "NORTH",
South = "SOUTH",
East = "EAST",
West = "WEST"
}
function move(direction: Direction, distance: number): void {
console.log(`Moving ${direction} by ${distance} units`);
}
move(Direction.North, 10);
// Moving NORTH by 10 units
// Type narrowing with discriminated unions
interface Circle {
kind: "circle";
radius: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Circle | Rectangle;
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
}
}
console.log(area({ kind: "circle", radius: 5 })); // 78.5398...
console.log(area({ kind: "rectangle", width: 4, height: 6 })); // 24
Utility Types
TypeScript provides built-in utility types for common type transformations.
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: Date;
}
// Partial — all properties optional
function updateTodo(todo: Todo, updates: Partial<Todo>): Todo {
return { ...todo, ...updates };
}
const todo: Todo = {
title: "Learn TypeScript",
description: "Study types and interfaces",
completed: false,
createdAt: new Date()
};
const updated = updateTodo(todo, { completed: true });
// Pick — select specific properties
type TodoPreview = Pick<Todo, "title" | "completed">;
// Omit — exclude specific properties
type TodoWithoutDates = Omit<Todo, "createdAt">;
// Readonly — all properties become readonly
type ImmutableTodo = Readonly<Todo>;
// Record — key-value map
type PageInfo = Record<string, { title: string; url: string }>;
const pages: PageInfo = {
home: { title: "Home", url: "/" },
about: { title: "About", url: "/about" }
};tsconfig and Compilation
The tsconfig.json file controls TypeScript compiler options.
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}tsc # compiles all files matching include patterns
tsc --watch # watch mode — recompiles on changesCommon Mistakes
1. Using any instead of proper types
any disables type checking. Use unknown when you truly don’t know the type, then narrow it.
2. Not enabling strict mode
// Without strict mode, TypeScript allows implicit any
function log(obj) { // parameter is implicitly any
console.log(obj);
}Set "strict": true in tsconfig.
3. Confusing interface with type
Interfaces can be extended and merged; type aliases can represent unions and primitives. Use interfaces for object shapes, types for everything else.
4. Forgetting to compile before running
TypeScript must be compiled to JavaScript. Use tsc or ts-node for development.
5. Incorrect null checking
function process(value: string | null) {
value.toUpperCase(); // Error: Object is possibly null
value!.toUpperCase(); // Non-null assertion (risky)
value?.toUpperCase(); // Safe — returns undefined if null
}6. Overusing as type assertions
Type assertions bypass the compiler. Use type narrowing (typeof, instanceof, discriminated unions) instead.
Practice Questions
What is the difference between
interfaceandtype? Interfaces can be extended, merged, and implemented by classes. Type aliases can represent unions, intersections, and primitives. Prefer interfaces for public API shapes.What does
strict: truedo in tsconfig? Enables all strict type-checking options: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, and more.What is a generic? A way to create reusable components that work with any type.
Array<T>is a generic — it works with any element type.How do you make a property optional? Add
?after the property name:age?: number.What does
Pick<T, K>do? Creates a type from T by selecting only the properties listed in K.Pick<Todo, "title">creates{ title: string }.
Challenge: Write a TypeScript function that takes an array of objects and a key, and returns a Map grouping objects by that key’s value with full type safety.
Mini Project — Typed API Client
Build a type-safe HTTP client using generics and TypeScript’s type system.
interface ApiResponse<T> {
data: T;
status: number;
ok: boolean;
}
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get<T>(endpoint: string): Promise<ApiResponse<T>> {
const response = await fetch(`${this.baseUrl}${endpoint}`);
const data = await response.json() as T;
return {
data,
status: response.status,
ok: response.ok
};
}
async post<T, R>(endpoint: string, body: T): Promise<ApiResponse<R>> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
const data = await response.json() as R;
return {
data,
status: response.status,
ok: response.ok
};
}
}
// Usage
interface User {
id: number;
name: string;
email: string;
}
interface CreateUserRequest {
name: string;
email: string;
}
async function main() {
const api = new ApiClient("https://api.example.com");
const users = await api.get<User[]>("/users");
console.log(`Fetched ${users.data.length} users`);
const newUser = await api.post<CreateUserRequest, User>(
"/users",
{ name: "Alice", email: "alice@example.com" }
);
console.log(`Created user: ${newUser.data.name}`);
}
main().catch(console.error);FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro