Object Static

============================================================================= Object static methods and typeof operator =============================================================================

// ── Object.keys ──────────────────────────────────────────────────────────────
// Returns a string[] of the object's field names in declaration order.
// The result array can be iterated directly without assigning to a variable.

const person: { name: string; age: number; city: string } = {
  name: 'Alice',
  age: 30,
  city: 'London',
}

for (const k of Object.keys(person)) {
  console.log(k)
}
// name
// age
// city

console.log(Object.keys(person).length)   // 3

// ── Object.values ─────────────────────────────────────────────────────────────
// Returns a string[] of each field value converted to a string.

for (const v of Object.values(person)) {
  console.log(v)
}
// Alice
// 30
// London

// ── Object.entries ────────────────────────────────────────────────────────────
// Returns a real [key, value] tuple array (values stringified) — destructure
// each entry positionally.

const dims: { width: number; height: number; depth: number } = {
  width: 100,
  height: 200,
  depth: 50,
}

for (const [key, value] of Object.entries(dims)) {
  console.log(key + ': ' + value)
}
// width: 100
// height: 200
// depth: 50

// ── for…in + Object.keys together ────────────────────────────────────────────
// for…in iterates field names directly, avoiding an intermediate array.

const scores: { math: number; english: number; science: number } = {
  math: 95,
  english: 88,
  science: 91,
}

for (const subject in scores) {
  console.log(subject)
}
// math
// english
// science

// ── Object.groupBy with inline key iteration ───────────────────────────────────
const fruits: string[] = ['apple', 'avocado', 'banana', 'blueberry', 'cherry']
const byLetter = Object.groupBy(fruits, (f) => f.substring(0, 1))

// Object.keys on a group map can be iterated directly
for (const letter of Object.keys(byLetter)) {
  console.log(letter)
}
// a
// b
// c

// ── Object.assign ─────────────────────────────────────────────────────────────
// Copies each source's fields into target, in argument order — a later
// source overwrites an earlier one on a shared field name. Mutates target in
// place (same heap object, no copy) and returns it.

interface Settings { theme: string; fontSize: number; darkMode: boolean }

const defaults: Settings = { theme: 'light', fontSize: 12, darkMode: false }
const userPrefs: Settings = { theme: 'dark', fontSize: 14, darkMode: true }

const applied = Object.assign(defaults, userPrefs)
console.log(applied.theme)      // dark
console.log(defaults.theme)     // dark (same object — assign mutates target)

// A source can supply just a subset of target's fields.
interface FontOnly { fontSize: number }
const bigFont: FontOnly = { fontSize: 20 }
Object.assign(defaults, bigFont)
console.log(defaults.fontSize)  // 20
console.log(defaults.darkMode)  // 1 (untouched — still true from userPrefs)

// Multiple sources apply in order; the last one wins on overlapping fields.
interface Counter { count: number }
const base: Counter = { count: 0 }
const step1: Counter = { count: 1 }
const step2: Counter = { count: 2 }
Object.assign(base, step1, step2)
console.log(base.count)         // 2

// ── Object.freeze / Object.seal ──────────────────────────────────────────────
// Object.freeze(obj) blocks writes to obj's existing fields — tracked by the
// object's own heap identity, not by the variable that froze it, so a write
// attempted through a different alias (another variable, a function
// parameter) is blocked too. Field-value mutation is the only thing freeze
// needs to actively enforce here: this compiler's objects are fixed-shape
// heap structs, so adding or deleting a field was already impossible before
// freeze existed, for any object. A blocked write throws a catchable Error.

interface Config { host: string; port: number }
const conf: Config = { host: 'localhost', port: 8080 }
Object.freeze(conf)

try {
  conf.port = 9090
} catch (e) {
  console.log('blocked: cannot write to a frozen object')
}
console.log(conf.port)   // 8080 (write was rejected, value unchanged)

// Freezing is per-object, not global — an unrelated object is unaffected.
const other: Config = { host: 'example.com', port: 443 }
other.port = 8443
console.log(other.port)  // 8443

// Object.seal(obj) is accepted but is a genuine no-op here: seal blocks
// adding/removing fields in real JS, which this compiler's objects already
// can't do at all — sealing changes nothing further, existing fields stay
// freely writable.
const sealed: Config = { host: 'sealed.example', port: 1 }
Object.seal(sealed)
sealed.port = 2
console.log(sealed.port)  // 2 (seal never blocked the value write)

// ── typeof ────────────────────────────────────────────────────────────────────
// Returns a string describing the compile-time type. Evaluated entirely at
// compile time — no code is emitted for the argument expression.

const nums: number[] = [1, 2, 3]

console.log(typeof 42)         // number
console.log(typeof 3.14)       // number
console.log(typeof 'hello')    // string
console.log(typeof true)       // boolean
console.log(typeof person)     // object
console.log(typeof nums)       // object  (arrays are objects)

function greet(x: string): string { return 'hi ' + x }
console.log(typeof greet)      // function
View source on GitHubexamples/objects/object_static.ts