TypeScript Essentials

1. Core Types

Q: Interface vs. Type Alias?
Declaration merging vs Unions.
Basic Implementation
// Interface (can be merged)
interface User { name: string; }
interface User { age: number; }

// Type (can define unions)
type ID = string | number;
Real World Example
// Use Interface for Object Shapes (e.g., React Props)
interface ButtonProps {
    label: string;
    onClick: () => void;
}

// Use Type for Unions or Complex Mappings
type ButtonVariant = 'primary' | 'secondary' | 'danger';
Show Answer

They are very similar, but:

  • Interface: Better for defining object shapes. Supports "Declaration Merging" (extending an interface by declaring it again).
  • Type: More flexible. Can define unions, primitives, and tuples.
// Interface
interface User {
  name: string;
}
interface User { // Merges with above
  age: number;
}

// Type
type Status = "success" | "error"; // Union (Interface can't do this)
Q: any vs. unknown?
Safety first.
Basic Implementation
let loose: any = 4;
loose.method(); // No error (dangerous)

let strict: unknown = 4;
// strict.method(); // Error: Object is of type 'unknown'
Real World Example
// Use 'unknown' for external data (e.g., API response)
function parseResponse(response: unknown) {
    if (typeof response === 'string') {
        return JSON.parse(response); // Safe now
    }
    throw new Error("Invalid response");
}
Show Answer

any: Turns off type checking. "I don't care." Dangerous.

unknown: "I don't know yet." You must check the type (narrowing) before using it. Safe.

let x: unknown = "hello";
// console.log(x.length); // Error: Object is of type 'unknown'.

if (typeof x === "string") {
  console.log(x.length); // OK
}

2. Generics

Q: What are Generics? Why use them?
Reusable components with type safety.
Basic Implementation
function identity<T>(arg: T): T {
    return arg;
}
const num = identity(5); // T is number
Real World Example
// Reusable API Response Wrapper
interface ApiResponse<Data> {
    status: number;
    data: Data;
    error?: string;
}

type UserResponse = ApiResponse<{ id: number; name: string }>;
Show Answer

Generics allow you to create reusable components/functions that work with multiple types while retaining type safety.

// Without Generics (Lost type info)
function identity(arg: any): any { return arg; }

// With Generics (Preserves type info)
function identity<T>(arg: T): T {
  return arg;
}

const num = identity(5); // TS knows 'num' is number
const str = identity("hi"); // TS knows 'str' is string
Q: Generics
Type variables.
Basic Implementation
function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>("myString");
Real World Example
// Reusable API Response Wrapper
interface ApiResponse<T> {
    data: T;
    status: number;
    error?: string;
}

// Usage
interface User { id: number; name: string; }
const response: ApiResponse<User> = await fetchUser();
Show Answer

Generics allow you to create reusable components that work with a variety of types rather than a single one. They act like variables for types.

3. Utility Types

Q: Explain Partial, Pick, and Omit.
Manipulating existing types.
Basic Implementation
interface Todo { id: number; title: string; desc: string; }

type P = Partial<Todo>; // { id?: number; title?: string; ... }
type K = Pick<Todo, 'title'>; // { title: string; }
type O = Omit<Todo, 'desc'>; // { id: number; title: string; }
Real World Example
// Updating a user profile (not all fields required)
function updateUser(id: number, fields: Partial<User>) {
  // ...
}

// Component Props excluding internal props
type PublicProps = Omit<ButtonProps, 'internalId'>;
Show Answer
interface Todo {
  id: number;
  title: string;
  desc: string;
}

// Partial: All properties become optional
type UpdateTodo = Partial<Todo>; // { id?: number, title?: string... }

// Pick: Select specific keys
type TodoPreview = Pick<Todo, "id" | "title">;

// Omit: Remove specific keys
type TodoInput = Omit<Todo, "id">;
Q: Utility Types (Pick, Omit, Partial)
Transforming types.
Examples
interface User {
    id: number;
    name: string;
    email: string;
}

// Pick: Select specific keys
type UserPreview = Pick<User, "id" | "name">;

// Omit: Remove specific keys
type UserInput = Omit<User, "id">;

// Partial: Make all keys optional
type UserUpdate = Partial<User>;
Show Answer

TypeScript provides built-in utility types to facilitate common type transformations.

  • Pick<T, K>: Constructs a type by picking the set of properties K from T.
  • Omit<T, K>: Constructs a type by picking all properties from T and then removing K.
  • Partial<T>: Constructs a type with all properties of T set to optional.
  • Record<K, T>: Constructs an object type whose property keys are K and whose property values are T.
Q: What is "Type Inference"?
Letting TS guess.
Basic Implementation
let x = 10; // TS infers x is number
// x = "hello"; // Error
Real World Example
// Return type inferred automatically
function add(a: number, b: number) {
  return a + b; // Inferred as number
}

// Array type inferred
const numbers = [1, 2, 3]; // number[]
Show Answer

TS automatically deduces the type based on the value. let x = 5; is inferred as number. You don't always need to write types explicitly.

Q: What is a "Tuple"?
Fixed length array.
Basic Implementation
let tuple: [string, number];
tuple = ["hello", 10]; // OK
// tuple = [10, "hello"]; // Error
Real World Example
// React Hooks return tuples
function useState<T>(initial: T): [T, (v: T) => void] {
  // ...
  return [state, setState];
}

const [count, setCount] = useState(0);
Show Answer

An array with a fixed number of elements whose types are known. let x: [string, number] = ["hello", 10];.

Q: What is "Union" vs "Intersection"?
OR vs AND.
Basic Implementation
type Union = string | number; // One OR the other
type Intersection = { a: string } & { b: number }; // Both
Real World Example
// Union: Handling different states
type State = { status: 'loading' } | { status: 'success', data: any };

// Intersection: Combining Props
type ButtonProps = BaseProps & { variant: 'primary' | 'secondary' };
Show Answer

Union (|): A value can be one of several types. string | number.

Intersection (&): Combines multiple types into one. TypeA & TypeB (must have properties of both).

Q: What is the `never` type?
Impossible state.
Basic Implementation
function throwError(msg: string): never {
  throw new Error(msg);
}
Real World Example
// Exhaustive checking in switch
function getArea(shape: Shape) {
  switch (shape.kind) {
    case 'circle': return ...;
    case 'square': return ...;
    default:
      const _exhaustiveCheck: never = shape; // Error if new shape added
      return _exhaustiveCheck;
  }
}
Show Answer

Represents values that never occur. Used for functions that throw errors or infinite loops, or for exhaustive checks in switch statements.

Q: What is `keyof` operator?
Getting keys as a union.
Basic Implementation
interface Person { name: string; age: number; }
type Keys = keyof Person; // "name" | "age"
Real World Example
// Type-safe property access
function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}
const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // OK
// getProperty(user, "email"); // Error
Show Answer

Takes an object type and produces a string or numeric literal union of its keys. keyof User might be "name" | "age".

4. Advanced Types & Features

Q: `void` vs `undefined`
Return types.
Basic Implementation
function log(): void { console.log("Hi"); }
function getVal(): undefined { return undefined; }
Real World Example
// Callback that doesn't return anything
function runCallback(cb: () => void) {
    cb();
}
// Even if cb returns something, it's ignored
Show Answer

void means a function doesn't return a value. undefined is a value. A function returning void can return undefined, but void is semantically "no return".

Q: `readonly` modifier
Immutability.
Basic Implementation
interface Config {
    readonly apiUrl: string;
}
const c: Config = { apiUrl: "http://..." };
// c.apiUrl = "new"; // Error
Real World Example
// Immutable State in Redux/Zustand
type State = {
    readonly count: number;
    readonly user: Readonly<User>;
};
Show Answer

Prevents a property of an object or class from being changed after initialization.

Q: `const` assertions
as const
Basic Implementation
let x = "hello" as const; // Type is "hello"
const arr = [1, 2] as const; // Type is readonly [1, 2]
Real World Example
// Redux Action Types
const ACTIONS = {
    LOGIN: 'LOGIN',
    LOGOUT: 'LOGOUT'
} as const;
// ACTIONS.LOGIN is type "LOGIN", not string
Show Answer

Tells the compiler to infer the narrowest possible type (literals) and make properties readonly. let x = "hello" as const; (Type is "hello", not string).

Q: Enums (String vs Numeric)
Named constants.
Basic Implementation
enum Direction { Up, Down, Left, Right } // 0, 1, 2, 3
enum Status { Success = "OK", Error = "ERR" }
Real World Example
// Better alternative: Union Types
type Status = 'loading' | 'success' | 'error';
// Less runtime overhead than Enums
Show Answer

Numeric: Auto-incrementing numbers. String: Explicit string values. Prefer Union Types over Enums in modern TS.

Q: Abstract Classes
Blueprints.
Basic Implementation
abstract class Animal {
    abstract makeSound(): void;
    move() { console.log("Moving"); }
}
Real World Example
// Base Service Class
abstract class BaseService<T> {
    abstract getAll(): Promise<T[]>;
    abstract getById(id: string): Promise<T>;
}
Show Answer

Classes that cannot be instantiated directly. Used as base classes for other classes to extend.

Q: Access Modifiers
public, private, protected.
Basic Implementation
class Car {
    public make: string;
    private vin: string;
    protected speed: number;
}
Real World Example
// Encapsulation in Services
class AuthService {
    private token: string;
    public login() { ... }
    private validateToken() { ... }
}
Show Answer
  • public: Accessible everywhere (default).
  • private: Accessible only within the class.
  • protected: Accessible within the class and subclasses.
Q: `implements` vs `extends`
Interface vs Class.
Basic Implementation
class Dog extends Animal { ... } // Inherits code
class Car implements Vehicle { ... } // Enforces shape
Real World Example
// React Class Components
class MyComp extends React.Component<Props> { ... }

// Custom Class implementing Interface
class LocalStorageService implements StorageService {
    save(key: string, val: string) { ... }
}
Show Answer

extends: Inherit from a class (code reuse). implements: Contract that a class must satisfy an interface (shape enforcement).

Q: Type Guards
Narrowing types.
Basic Implementation
if (typeof x === "string") { ... }
if (x instanceof Date) { ... }
if ("role" in user) { ... }
Real World Example
// Handling API Errors
try {
    await apiCall();
} catch (e) {
    if (e instanceof Error) {
        console.log(e.message);
    }
}
Show Answer

Techniques to narrow down the type of a variable within a conditional block. typeof, instanceof, in.

Q: User-Defined Type Guards
is keyword.
Basic Implementation
function isString(x: any): x is string {
    return typeof x === "string";
}
Real World Example
// Validating API Data
interface User { id: number; name: string; }
function isUser(obj: any): obj is User {
    return obj && typeof obj.id === 'number';
}
Show Answer
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
Q: Discriminated Unions
Common property.
Basic Implementation
type Shape = 
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };
Real World Example
// Redux Actions
type Action = 
  | { type: 'LOGIN_SUCCESS'; payload: User }
  | { type: 'LOGIN_FAIL'; error: string };

function reducer(state: State, action: Action) {
    if (action.type === 'LOGIN_SUCCESS') {
        // action.payload is available
    }
}
Show Answer

A pattern where every type in a union has a common literal property (the discriminant) used to narrow the type.

interface Circle { kind: "circle"; radius: number; }
interface Square { kind: "square"; side: number; }
type Shape = Circle | Square;
Q: Non-null assertion operator (`!`)
Trust me.
Basic Implementation
const el = document.getElementById("app")!;
// I know 'app' exists, so don't worry TS.
Real World Example
// Refs in React (sometimes)
const inputRef = useRef<HTMLInputElement>(null);
// Later...
inputRef.current!.focus();
Show Answer

Tells TS that a value is not null or undefined, even if the type suggests it might be. Use with caution.

Q: Generic Constraints
extends keyword.
Basic Implementation
function getLength<T extends { length: number }>(arg: T) {
    return arg.length;
}
Real World Example
// React Component Props Constraint
interface BaseProps { id: string; }
function Card<T extends BaseProps>(props: T) {
    return <div id={props.id}>...</div>;
}
Show Answer

Restricting the types that can be used with a generic. function logLength<T extends { length: number }>(arg: T).

Q: `Record<K, T>`
Utility type.
Basic Implementation
type Scores = Record<string, number>;
const s: Scores = { "Alice": 10, "Bob": 20 };
Real World Example
// Mapping IDs to Data
type UserMap = Record<number, User>;
const usersById: UserMap = {
    1: { id: 1, name: "Alice" },
    2: { id: 2, name: "Bob" }
};
Show Answer

Constructs an object type whose property keys are K and whose property values are T.

Q: `Exclude<T, U>`
Removing types.
Basic Implementation
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
Real World Example
// Removing specific keys from a union of keys
type AllKeys = "id" | "name" | "email";
type PublicKeys = Exclude<AllKeys, "email">;
Show Answer

Constructs a type by excluding from T all union members that are assignable to U.

Q: `Extract<T, U>`
Keeping types.
Basic Implementation
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
Real World Example
// Extracting common types from two unions
type Common = Extract<TypeA | TypeB, TypeC>;
Show Answer

Constructs a type by extracting from T all union members that are assignable to U.

Q: `NonNullable<T>`
No nulls.
Basic Implementation
type T0 = NonNullable<string | number | undefined>; // string | number
Real World Example
// Ensuring a prop is present
type Props = { title?: string };
function render(title: NonNullable<Props['title']>) {
    // title is string, not undefined
}
Show Answer

Constructs a type by excluding null and undefined from T.

Q: `ReturnType<T>`
Function return.
Basic Implementation
function getUser() { return { name: "Alice", age: 20 }; }
type User = ReturnType<typeof getUser>;
Real World Example
// Getting Redux State type from reducer
type RootState = ReturnType<typeof rootReducer>;
Show Answer

Constructs a type consisting of the return type of function T.

Q: `Parameters<T>`
Function args.
Basic Implementation
function add(a: number, b: number) {}
type Args = Parameters<typeof add>; // [number, number]
Real World Example
// Reusing function parameters for a wrapper
type HandlerArgs = Parameters<typeof eventHandler>;
function wrapper(...args: HandlerArgs) {
    console.log("Called");
    eventHandler(...args);
}
Show Answer

Constructs a tuple type from the types used in the parameters of a function type T.

Q: Mapped Types
Iterating keys.
Basic Implementation
type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};
Real World Example
// Creating a validation schema type from a model
type Validator<T> = {
    [P in keyof T]: (value: T[P]) => boolean;
};
Show Answer

Creating new types based on old ones by iterating over property keys. { [P in K]: T }.

Q: Conditional Types
Ternary for types.
Basic Implementation
type IsString<T> = T extends string ? true : false;
Real World Example
// Flattening Array Types
type Flatten<T> = T extends any[] ? T[number] : T;
type Str = Flatten<string[]>; // string
Show Answer

T extends U ? X : Y. Selects one of two types based on a condition.

Q: Template Literal Types
String manipulation.
Basic Implementation
type World = "world";
type Greeting = `hello ${World}`; // "hello world"
Real World Example
// Generating Event Names
type Event = "click" | "hover";
type Handler = `on${Capitalize<Event>}`; // "onClick" | "onHover"
Show Answer

Builds types via string interpolation. type Greeting = `Hello ${string}`;.

Q: `infer` keyword
Type inference in conditionals.
Basic Implementation
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
Real World Example
// Unpacking Promise types
type Unpack<T> = T extends Promise<infer U> ? U : T;
type Data = Unpack<Promise<string>>; // string
Show Answer

Used within conditional types to infer a type variable to be used in the true branch.

Q: `declare` keyword
Ambient declaration.
Basic Implementation
declare const myLibrary: any;
Real World Example
// Declaring global variables injected by build tools
declare const __DEV__: boolean;
if (__DEV__) { console.log("Debug mode"); }
Show Answer

Used to tell the compiler about variables/functions that exist elsewhere (e.g., from a CDN script) without defining implementation.

Q: `.d.ts` files
Type definitions.
Basic Implementation
// my-lib.d.ts
export function doSomething(a: string): number;
Real World Example
// Adding types to untyped JS libraries
// npm install @types/lodash
Show Answer

Files that contain only type information, no executable code. Used to provide types for JS libraries.

Q: `tsconfig.json`
Configuration.
Basic Implementation
{
  "compilerOptions": {
    "target": "es6",
    "strict": true
  }
}
Real World Example
// Path Aliases
"paths": {
  "@components/*": ["src/components/*"]
}
Show Answer

Root file of a TS project. Configures compiler options like target, module, strict, etc.

Q: Module Resolution
Finding files.
Basic Implementation
import { x } from "./file"; // Relative
import { y } from "react"; // Node_modules
Real World Example
// Configuring "baseUrl" and "paths" in tsconfig
// to support absolute imports
Show Answer

The process the compiler uses to figure out what an import refers to (Classic vs Node).

Q: Namespaces
Internal modules.
Basic Implementation
namespace Utils {
    export function log(msg: string) { ... }
}
Utils.log("Hi");
Real World Example
// Mostly legacy. Use ES Modules instead.
// Sometimes used for merging types with classes/functions.
Show Answer

Older way to organize code. Modern TS prefers ES Modules (import/export). Avoid namespaces in new code.

Q: `Required<T>`
Opposite of Partial.
Basic Implementation
interface Props { a?: number; }
type AllProps = Required<Props>; // { a: number; }
Real World Example
// Ensuring all config options are present internally
function init(config: Config) {
    const fullConfig: Required<Config> = { ...defaults, ...config };
}
Show Answer

Constructs a type consisting of all properties of T set to required.

Q: `Readonly<T>`
Immutable object.
Basic Implementation
interface Todo { title: string; }
const todo: Readonly<Todo> = { title: "Buy milk" };
// todo.title = "New"; // Error
Real World Example
// Freezing state in functional programming
function update(state: Readonly<State>) {
    return { ...state, count: state.count + 1 };
}
Show Answer

Constructs a type with all properties of T set to readonly.

Q: Covariance vs Contravariance
Type compatibility.
Basic Implementation
// Covariant: Return types (Dog -> Animal)
// Contravariant: Argument types (Animal -> Dog)
Real World Example
// Assigning functions
type Logger = (msg: string) => void;
let log: Logger;
let logAny = (msg: any) => console.log(msg);
log = logAny; // OK (Contravariance)
Show Answer

Complex topic regarding how subtypes relate to supertypes in complex structures (like function args vs return types).

Q: Function Overloading
Multiple signatures.
Basic Implementation
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
    if (d !== undefined && y !== undefined) {
        return new Date(y, mOrTimestamp, d);
    } else {
        return new Date(mOrTimestamp);
    }
}
Real World Example
// jQuery-style APIs
// $(selector) vs $(element) vs $(callback)
Show Answer

Defining multiple function signatures for a single implementation to handle different argument combinations.

Q: Index Signatures
Dynamic keys.
Basic Implementation
interface StringArray {
    [index: number]: string;
}
const myArray: StringArray = ["Bob", "Fred"];
Real World Example
// Dictionary / Map
interface Cache {
    [key: string]: any;
}
const cache: Cache = {};
cache["user_1"] = { ... };
Show Answer

Defining types for objects when you don't know the property names ahead of time. { [key: string]: number }.

Q: Hybrid Types
Function + Object.
Basic Implementation
interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}
Real World Example
// Libraries like Axios or jQuery
// axios('url') // function
// axios.get('url') // object property
Show Answer

An object that acts as both a function and an object (has properties). Common in libraries like jQuery or Axios.

Q: `OmitThisParameter`
Utility.
Basic Implementation
function toHex(this: Number) {
    return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
Real World Example
// Binding methods in classes or utilities
// to ensure 'this' is handled correctly.
Show Answer

Removes the this parameter from a function type.

Q: `ThisType<T>`
Contextual this.
Basic Implementation
type ObjectDescriptor<D, M> = {
    data?: D;
    methods?: M & ThisType<D & M>; // 'this' inside methods is D & M
};
Real World Example
// Vue 2 Options API
// 'this' in methods refers to data + props + methods
Show Answer

Marker utility type used to enable contextual this type in object literals.

Q: Structural Typing
Duck typing.
Basic Implementation
interface Point { x: number; y: number; }
function logPoint(p: Point) { console.log(p); }

const point3D = { x: 1, y: 2, z: 3 };
logPoint(point3D); // OK (has x and y)
Real World Example
// Mocking objects for testing
// You only need to match the required shape, not the exact class.
Show Answer

TS uses structural typing: if it looks like a duck (has same props), it is a duck. Names don't matter, shape does.

Q: Nominal Typing
Branding.
Basic Implementation
type USD = number & { __brand: "USD" };
type EUR = number & { __brand: "EUR" };

let usd = 10 as USD;
let eur = 10 as EUR;
// usd = eur; // Error
Real World Example
// Preventing mixing up units (e.g. meters vs feet)
// or validated strings (e.g. EmailAddress vs string)
Show Answer

TS doesn't support this natively, but you can simulate it using "Branding" (adding a unique property) to distinguish types with the same shape.

Q: `satisfies` operator
Validation without widening.
Basic Implementation
type Colors = "red" | "green" | "blue";
type RGB = [number, number, number];

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;
Real World Example
// palette.red is inferred as [number, number, number]
// palette.green is inferred as string
// We get type checking AND specific inference.
Show Answer

Validates that an expression matches a type, but preserves the more specific type of the expression for inference.

Q: Recursive Types
JSON.
Basic Implementation
type Json = 
    | string | number | boolean | null
    | Json[]
    | { [key: string]: Json };
Real World Example
// Nested Comment Structure
interface Comment {
    text: string;
    replies: Comment[];
}
Show Answer

Types that reference themselves. Example: JSON object type.