Episode 1 — Fundamentals / 1.25 — TypeScript Essentials

1.25 — TypeScript Essentials: Quick Revision

Compact cheat sheet. Print-friendly.

How to use this material (instructions)

  1. Skim before labs or interviews.
  2. Drill gaps — reopen README.md then 1.25.a through 1.25.l.
  3. Practice1.25-Exercise-Questions.md.
  4. Polish answers1.25-Interview-Questions.md.

Core vocabulary

TermOne-liner
TypeScriptTyped superset of JavaScript that compiles to plain JS
Type annotationExplicit type label: let x: string
Type inferenceTS automatically determines types from context
Compile timeWhen tsc checks types — before code runs
tscTypeScript compiler — type-checks and emits JS
tsconfig.jsonConfiguration file for the TS compiler
Declaration file.d.ts — type definitions without implementation

Basic types

TypeExampleNotes
string"hello"Text
number42, 3.14All numbers (no int/float split)
booleantrueLogical
anylet x: anyOpts out of checking (avoid!)
unknownlet x: unknownSafe any — must narrow first
void(): voidFunction returns nothing
nullnullIntentional absence
undefinedundefinedNot assigned
never(): neverNever returns (throws/infinite loop)
bigint42nLarge integers

Type annotation syntax

// Variables
let name: string = "Alice";
let age: number = 30;

// Function parameters and return
function greet(name: string): string { return `Hi, ${name}`; }

// Arrow function
const add = (a: number, b: number): number => a + b;

// Arrays
let names: string[] = ["Alice", "Bob"];
let nums: Array<number> = [1, 2, 3];

// Tuples
let pair: [string, number] = ["Alice", 30];

// Object
let user: { name: string; age: number } = { name: "Alice", age: 30 };

Interface vs type

// Interface — object shape
interface User {
  id: number;
  name: string;
  email?: string;          // Optional
  readonly role: string;   // Cannot reassign
}

// Type alias — any type
type ID = string | number;
type Status = "active" | "inactive";
type Pair = [string, number];
type Callback = (data: string) => void;
Featureinterfacetype
Object shapeYesYes
Extendsextends&
Declaration mergingYesNo
implementsYesNo
UnionsNoYes
TuplesNoYes
PrimitivesNoYes

Default: interface for objects, type for everything else.


Union and intersection

// Union — one OF several types
let id: string | number;

// Intersection — ALL types combined
type Admin = User & { permissions: string[] };

// Discriminated union
type Shape =
  | { type: "circle"; radius: number }
  | { type: "square"; side: number };

Type narrowing

// typeof
if (typeof x === "string") { x.toUpperCase(); }

// instanceof
if (error instanceof Error) { error.message; }

// in operator
if ("fly" in animal) { animal.fly(); }

// Discriminant
switch (shape.type) {
  case "circle": shape.radius; break;
  case "square": shape.side; break;
}

// Custom type guard
function isCat(a: Cat | Dog): a is Cat { return "meow" in a; }

Generics

// Generic function
function identity<T>(value: T): T { return value; }

// Generic interface
interface Box<T> { value: T; }

// Generic with constraint
function logLength<T extends { length: number }>(x: T): void {
  console.log(x.length);
}

// Multiple type params
function pair<A, B>(a: A, b: B): [A, B] { return [a, b]; }

// Default type parameter
interface Container<T = string> { value: T; }

Utility types

UtilityWhat it doesExample
Partial<T>All props optionalPartial<User>
Required<T>All props requiredRequired<Config>
Pick<T, K>Keep only KPick<User, "id" | "name">
Omit<T, K>Remove KOmit<User, "password">
Record<K, V>Object from key/valueRecord<string, number>
Readonly<T>All props readonlyReadonly<State>
ReturnType<F>Function return typeReturnType<typeof fn>
Parameters<F>Function param typesParameters<typeof fn>
NonNullable<T>Remove null/undefinedNonNullable<string | null>
Exclude<T, U>Remove from unionExclude<"a"|"b"|"c", "a">
Extract<T, U>Keep in unionExtract<"a"|"b"|"c", "a">

keyof and mapped types

// keyof — union of property names
type UserKeys = keyof User;  // "id" | "name" | "email"

// Type-safe property access
function get<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Mapped type — transform each property
type Stringify<T> = { [K in keyof T]: string };
type Flags<T> = { [K in keyof T]: boolean };

Enums and literal types

// String enum
enum Status { Active = "ACTIVE", Inactive = "INACTIVE" }

// Literal union (often preferred)
type Status = "active" | "inactive";
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

// as const — makes values literal and readonly
const config = { port: 3000, host: "localhost" } as const;

tsconfig.json key options

OptionPurposeRecommended
targetJS output version"ES2020"
moduleModule system"commonjs" (Node) or "ESNext" (bundler)
strictAll strict checkstrue (always)
outDirOutput directory"./dist"
rootDirSource directory"./src"
libBuilt-in type libs["ES2020", "DOM"]
jsxJSX handling"react-jsx"
moduleResolutionImport resolution"bundler" or "node"
esModuleInteropDefault import fixtrue
skipLibCheckSkip .d.ts checkingtrue
noEmitType-check onlytrue (when bundler compiles)
declarationGenerate .d.tstrue (for libraries)
sourceMapGenerate .js.maptrue (for debugging)
includeFiles to compile["src/**/*"]
excludeFiles to skip["node_modules", "dist"]

Compiler commands

npx tsc                    # Compile project
npx tsc hello.ts           # Compile single file
npx tsc --watch            # Watch mode
npx tsc --noEmit           # Type-check only
npx tsc --init             # Create tsconfig.json
npx tsc --noEmitOnError    # No output if errors
npx tsc --build            # Build project references

Running TypeScript

ToolType-checks?SpeedUse case
tscYesModerateProduction build, CI
tsc --noEmitYesModerateType checking only
ts-nodeYes (default)SlowScripts, REPL
tsxNoFastDevelopment
Vite/esbuildNoVery fastBundled apps

Dev workflow: tsx watch for running + tsc --noEmit --watch for type checking.


ESLint + Prettier

# Install
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm install -D prettier eslint-config-prettier
npm install -D husky lint-staged

ESLint = code quality (bugs, patterns). Prettier = formatting (whitespace, quotes). eslint-config-prettier = disables ESLint formatting rules that conflict with Prettier.

Key TS ESLint rules

RulePurpose
no-explicit-anyBan any usage
no-unused-varsCatch dead code
no-floating-promisesUnhandled promises
consistent-type-importsUse import type

CI pipeline order

1. typecheck   → tsc --noEmit
2. lint        → eslint src/
3. format      → prettier --check src/
4. test        → vitest run
5. build       → vite build (or tsc)

Common patterns

// Nullable
function find(id: number): User | null { /* ... */ }

// Optional chaining + nullish coalescing
const name = user?.profile?.name ?? "Anonymous";

// Type assertion (use sparingly)
const input = document.getElementById("email") as HTMLInputElement;

// Discriminated union + exhaustive check
function handle(action: Action): State {
  switch (action.type) {
    case "increment": return state + action.amount;
    case "reset": return 0;
    default: const _: never = action; return _;
  }
}

// Generic API wrapper
async function fetchData<T>(url: string): Promise<T> {
  const res = await fetch(url);
  return res.json();
}
const users = await fetchData<User[]>("/api/users");

Master workflow

  1. Define types — interfaces, type aliases for data shapes.
  2. Write signatures — function inputs/outputs (types-first).
  3. Implement — let autocomplete and errors guide you.
  4. Refactor — compiler flags every breakage.
  5. Lint + format — ESLint + Prettier on save.
  6. Commit — husky + lint-staged enforce quality.
  7. CI — typecheck + lint + format + test + build.

End of 1.25 quick revision.