Skip to content

TypeScript Basics

TypeScript is a superset of JavaScript that adds static typing. Key features: type annotations, interfaces, generics, enums, union/intersection types, and decorators. TypeScript compiles to JavaScript and catches errors at compile time rather than runtime. Angular is built entirely with TypeScript.


Type System

TypeScript provides: primitive types (string, number, boolean), arrays (number[] or Array<number>), tuples ([string, number]), enums, any (opt-out of type checking), unknown (safe any — must narrow before use), void (no return), never (unreachable code). Use unknown over any for safety.

Deep Dive: Examples
// Primitives
let name: string = "John";
let age: number = 30;
let active: boolean = true;

// Arrays & Tuples
let scores: number[] = [90, 85, 92];
let pair: [string, number] = ["John", 30];

// Enum
enum Status { Active, Inactive, Pending }
let s: Status = Status.Active;  // 0

// String enum (preferred for readability)
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT" }

// Union types — value can be one of several types
let id: string | number = "abc";
id = 123;  // also valid

// Literal types — restrict to specific values
type Theme = "light" | "dark";

// any vs unknown
let a: any = 5;
a.toUpperCase();       // compiles but crashes at runtime

let u: unknown = 5;
// u.toUpperCase();    // ❌ compile error — must narrow first
if (typeof u === "string") {
    u.toUpperCase();   // ✅ safe after narrowing
}

Interfaces & Types

Interfaces define object shapes — can be extended and implemented by classes. Type aliases can define unions, intersections, and primitives. Use interfaces for object shapes, type aliases for unions/composites. Both support optional (?) and readonly properties.

Deep Dive: Interface vs Type
// Interface — object shape
interface User {
    id: number;
    name: string;
    email?: string;           // optional
    readonly createdAt: Date; // immutable
}

// Extending interfaces
interface Admin extends User {
    role: string;
    permissions: string[];
}

// Type alias — more flexible
type ID = string | number;
type Callback = (data: string) => void;
type Result = { success: boolean; data?: any };

// Intersection type (combine types)
type AdminUser = User & { role: string };

// Interface vs Type
// - Interface: extendable, mergeable (declaration merging), use for objects
// - Type: unions, intersections, primitives, mapped types

Generics

Generics let you write reusable code that works with multiple types while maintaining type safety. Use <T> as a type parameter. Common in functions, classes, and interfaces. Can constrain with extends.

Deep Dive: Examples
// Generic function
function identity<T>(value: T): T {
    return value;
}
identity<string>("hello");  // explicit
identity(42);               // inferred as number

// Generic interface
interface ApiResponse<T> {
    data: T;
    status: number;
    message: string;
}

const userResponse: ApiResponse<User> = {
    data: { id: 1, name: "John", createdAt: new Date() },
    status: 200,
    message: "OK"
};

// Constrained generic
function getLength<T extends { length: number }>(item: T): number {
    return item.length;
}
getLength("hello");     // ✅ string has .length
getLength([1, 2, 3]);   // ✅ array has .length
// getLength(42);       // ❌ number has no .length

Decorators

Decorators are metadata annotations used heavily in Angular: @Component, @Injectable, @Input, @Output, @NgModule. They are functions that modify classes, methods, or properties at design time. Angular uses them for dependency injection, component configuration, and more.

Deep Dive: Types of Decorators
// Class decorator
function Logger(target: Function) {
    console.log("Creating:", target.name);
}

@Logger
class UserService { }

// Decorator factory (with parameters)
function Component(config: { selector: string; template: string }) {
    return function (target: Function) {
        // attach metadata to the class
    };
}

@Component({
    selector: 'app-user',
    template: '<h1>User</h1>'
})
class UserComponent { }

// Angular decorators you'll use:
// @Component   — defines a component
// @NgModule    — defines a module
// @Injectable  — marks a class for DI
// @Input       — parent-to-child data binding
// @Output      — child-to-parent event emission
// @ViewChild   — access child component/element
// @Pipe        — defines a custom pipe

Utility Types

TypeScript provides built-in utility types: Partial<T> (all properties optional), Required<T> (all required), Readonly<T> (immutable), Pick<T, K> (subset of properties), Omit<T, K> (exclude properties), Record<K, V> (key-value map).

Deep Dive: Examples
interface User {
    id: number;
    name: string;
    email: string;
}

// Partial — all optional (great for updates)
function updateUser(id: number, updates: Partial<User>) { }
updateUser(1, { name: "New Name" });  // only pass what changed

// Pick — subset of properties
type UserPreview = Pick<User, "id" | "name">;

// Omit — exclude properties
type CreateUser = Omit<User, "id">;  // no id when creating

// Record — key-value map
type UserRoles = Record<string, string[]>;
const roles: UserRoles = { admin: ["read", "write"], user: ["read"] };

// Readonly — immutable
const config: Readonly<User> = { id: 1, name: "John", email: "j@test.com" };
// config.name = "Jane";  // ❌ compile error

Common Interview Questions

Common Interview Questions
  • What is TypeScript? How is it different from JavaScript?
  • What is the difference between interface and type?
  • What is any vs unknown?
  • What are generics? Give an example.
  • What are decorators in Angular?
  • What are union and intersection types?
  • What are utility types? Name some.
  • What is type narrowing?