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
interfaceandtype? - What is
anyvsunknown? - 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?