💡 Running TypeScript
TypeScript requires compilation to JavaScript. To practice:
npm install -g typescripttsc filename.tsMaster TypeScript's type system to catch bugs at compile-time, enable better tooling, and write more maintainable code. Learn types, interfaces, generics, and utility types.
JavaScript is dynamically typed — variables can hold any value, functions accept anything, and errors only appear at runtime. TypeScript adds a compile-time type system that catches bugs before your code runs.
Type annotations tell TypeScript exactly what kind of value a variable, parameter, or return value should hold.
TypeScript primitive types, arrays, objects, and functions
// TypeScript Basic Type Annotations
// Primitive types
let name: string = "Boopie";
let age: number = 16;
let alive: boolean = true;
// Arrays
let scores: number[] = [10, 20, 30];
let names: string[] = ["Alice", "Bob"];
let mixed: (string | number)[] = [1, "two", 3];
// Objects
let user: { name: string; age: number } = {
name: "Boopie",
age: 16
};
// Functions with types
function add(a: number, b: number): number {
return a + b;
}
// Arrow functions with types
const multiply = (x: nu
...Interfaces describe the shape of objects. They define what properties an object must have and their types, making your code predictable and self-documenting.
Define object shapes with optional and readonly properties
// Interfaces - Describe Object Shapes
interface User {
name: string;
age: number;
email: string;
active: boolean;
}
// Using the interface
const user: User = {
name: "Boopie",
age: 16,
email: "boopie@example.com",
active: true
};
// Optional properties
interface Product {
id: number;
name: string;
description?: string; // optional
price: number;
}
const product: Product = {
id: 1,
name: "Widget",
price: 29.99
// description is optional, so we can omit it
};
...Type aliases create reusable type definitions. Union types allow a value to be one of several types, while literal types restrict values to specific options.
Create reusable types and union/intersection types
// Type Aliases & Union Types
// Type alias for primitives
type ID = string | number;
let userId: ID = 123;
userId = "abc-123"; // Both are valid
// Type alias for objects
type Point = {
x: number;
y: number;
};
const origin: Point = { x: 0, y: 0 };
// Union types - multiple possible types
type Status = "pending" | "approved" | "rejected";
let orderStatus: Status = "pending";
orderStatus = "approved"; // ✓ OK
// orderStatus = "unknown"; // ❌ Error!
// Literal types
type Size = "sm"
...Generics create reusable, type-safe components that work with any type. They're essential for building libraries, APIs, and flexible utilities.
Create reusable, type-safe components that work with any type
// Generics - Reusable Type-Safe Code
// Generic function
function identity<T>(value: T): T {
return value;
}
// Usage - type is inferred or explicit
const num = identity(42); // T is number
const str = identity<string>("hi"); // T is string
// Generic with arrays
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
const first = firstElement([1, 2, 3]); // number | undefined
const firstStr = firstElement(["a", "b"]); // string | undefined
// Generic inte
...💡 Key Insight: Generics are type placeholders. When you call a generic function, TypeScript infers or you specify the actual type, giving you full type safety without duplicating code.
Type narrowing lets TypeScript understand the specific type within conditional blocks. Discriminated unions are the most powerful pattern for complex data.
Use typeof, instanceof, and discriminated unions
// Type Narrowing & Type Guards
// typeof narrowing
function printValue(value: string | number) {
if (typeof value === "string") {
// TS knows value is string here
console.log(value.toUpperCase());
} else {
// TS knows value is number here
console.log(value.toFixed(2));
}
}
// instanceof narrowing
class Dog {
bark() { console.log("Woof!"); }
}
class Cat {
meow() { console.log("Meow!"); }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
an
...TypeScript includes powerful built-in utility types that transform existing types. These are essential for everyday TypeScript development.
Built-in type transformers like Partial, Pick, Omit, and Record
// Utility Types - Built-in Type Transformers
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Partial<T> - Make all properties optional
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; ... }
function updateUser(id: number, updates: Partial<User>) {
// Can pass any subset of User properties
}
updateUser(1, { name: "New Name" }); // ✓ OK
// Required<T> - Make all properties required
interface Confi
...Advanced type transformations let you create new types programmatically. These power the utility types and enable sophisticated type logic.
Advanced type transformations and conditional logic
// Mapped Types & Conditional Types
// Basic mapped type
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};
// Real example
interface User {
id: number;
name: string;
email: string;
}
type ReadonlyUser = Readonly<User>;
// All properties are now readonly
// Mapped type with transformation
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<User>;
// { getId: () => numb
...TypeScript fully understands asynchronous code. Type your async functions, API responses, and error handling for complete safety.
Type async functions, API responses, and error handling
// Async Types & Promise Handling
// Typing async functions
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Using the Awaited utility type
type ResolvedUser = Awaited<ReturnType<typeof fetchUser>>;
// User
// Promise with union types
type ApiResult<T> =
| { success: true; data: T }
| { success: false; error: string };
async function fetchData(): Promise<ApiResult<User[]>> {
try {
const response
...Decorators are a meta-programming feature for modifying classes, methods, and properties. They're used extensively in Angular, NestJS, and TypeORM.
Meta-programming for classes, methods, and properties
// Decorators - Metaprogramming for Classes
// Enable in tsconfig.json: "experimentalDecorators": true
// Class decorator
function Logger(constructor: Function) {
console.log("Class created:", constructor.name);
}
@Logger
class User {
constructor(public name: string) {}
}
// Logs: "Class created: User"
// Decorator factory - returns a decorator
function Component(config: { selector: string }) {
return function(constructor: Function) {
console.log("Component:", config.selector);
};
...Declaration files (.d.ts) add type information to JavaScript libraries. Module augmentation lets you extend existing types.
Add type information to JavaScript libraries
// Declaration Files (.d.ts) - Adding Types to JS Libraries
// Creating a declaration file for a JavaScript library
// utils.d.ts
declare module "my-utils" {
export function sum(a: number, b: number): number;
export function capitalize(str: string): string;
export const VERSION: string;
}
// Now you can import with full type support
// import { sum, capitalize, VERSION } from "my-utils";
// Ambient declarations for global variables
declare const API_URL: string;
declare const DEBUG: boo
...Sign up for free to track which lessons you've completed and get learning reminders.