“TypeScript is not making your life terrible. It’s just showing you how terrible your life already is.”
What it means: TypeScript checks your code before it runs and blocks invalid usage.
function greet(user: { name: string }) {return user.name.toUpperCase()}greet({ age: 25 })// ❌ Error: Property 'name' is missing
Why it matters: Without TypeScript, this crashes at runtime. With TypeScript, it never ships.
type, interface, enumtypeDefines a data shape.
type User = { id: number; name: string }
interfaceLike type, but extendable and mergeable.
interface User {id: numbername: string}
Use interface for public object APIs.
enumRepresents a fixed set of named values.
enum Status {Loading,Success,Error,}
What it means: Restricting values to specific allowed options.
type Operator = "+" | "-" | "*" | "/"
Now "%" is rejected at compile time.
What it means: Creating types automatically from real values.
const operations = {"+": (a: number, b: number) => a + b,"-": (a: number, b: number) => a - b,}type Operator = keyof typeof operations
Why it matters:
When you change operations, Operator updates automatically.
keyof and typeoftypeofGets the type of a runtime value.
type Ops = typeof operations
keyofExtracts keys as a union.
type Operator = keyof Ops
What it means: Write reusable, type-safe code.
function identity<T>(value: T): T {return value}
TypeScript infers T automatically.
Record<K, T>What it does: Enforces exact keys and consistent value types.
type OperationFn = (a: number, b: number) => numberconst operations: Record<Operator, OperationFn> = { ... }
Now you can’t miss keys or add wrong ones.
Partial<T>What it does: Makes all fields optional.
type PartialUser = Partial<User>
Pick<T, K>What it does: Selects specific fields.
type UserName = Pick<User, "name">
Omit<T, K>What it does: Removes specific fields.
type UserWithoutId = Omit<User, "id">
satisfies operatorWhat it does: Checks shape without losing inference.
const operations = {"+": (a: number, b: number) => a + b,"-": (a: number, b: number) => a - b,} satisfies Record<Operator, OperationFn>
Why it’s better than : Record<...>
any vs unknown vs neveranyTurns off type safety.
let v: any = 10v.foo.bar() // allowed, unsafe
unknownForces validation.
let v: unknown = "hello"if (typeof v === "string") {v.toUpperCase() // safe}
neverRepresents impossible values.
function fail(): never {throw new Error("Crash")}
Also used for exhaustive checks.
Here’s the concise version:
Safe = TypeScript can guarantee it won’t crash at runtime. Unsafe = TypeScript has to trust you.
any → disables type checkingas SomeType (casts) → you might lie to the compilerunknown without checks// @ts-ignore, non-null !let v: any = 10v.foo.bar() // allowed, unsafe
unknown + runtime checks"a" | "b")keyof typeofsatisfiesneverlet v: unknown = "hi"if (typeof v === "string") {v.toUpperCase() // safe}