Skip to content

isObject

Checks whether a value is of object type.

Basic Usage

typescript
import { isObject } from 'radash'

console.log(isObject({}))                    // true
console.log(isObject([]))                    // true
console.log(isObject(new Date()))           // true
console.log(isObject(null))                 // false
console.log(isObject(undefined))            // false
console.log(isObject('hello'))              // false
console.log(isObject(123))                  // false

Syntax

typescript
function isObject(value: any): value is object

Parameters

  • value (any): The value to check

Return Value

Returns a boolean value, true if the value is an object, false otherwise. Also serves as a TypeScript type guard.

Examples

Basic Type Checking

typescript
import { isObject } from 'radash'

// Object types
console.log(isObject({}))                    // true
console.log(isObject({ name: 'Alice' }))    // true
console.log(isObject([]))                    // true
console.log(isObject([1, 2, 3]))            // true
console.log(isObject(new Date()))           // true
console.log(isObject(new RegExp('test')))   // true
console.log(isObject(new Map()))            // true
console.log(isObject(new Set()))            // true

// Non-object types
console.log(isObject(null))                 // false
console.log(isObject(undefined))            // false
console.log(isObject('hello'))              // false
console.log(isObject(123))                  // false
console.log(isObject(true))                 // false
console.log(isObject(false))                // false
console.log(isObject(() => {}))             // false

Special Object Checking

typescript
import { isObject } from 'radash'

// Built-in objects
console.log(isObject(new Array()))          // true
console.log(isObject(new Object()))         // true
console.log(isObject(new String('hello'))) // true
console.log(isObject(new Number(123)))     // true
console.log(isObject(new Boolean(true)))   // true

// Function objects
console.log(isObject(function() {}))        // false
console.log(isObject(() => {}))             // false
console.log(isObject(async () => {}))       // false

// Primitive wrapper objects
console.log(isObject(new String('hello'))) // true
console.log(isObject(new Number(123)))     // true
console.log(isObject(new Boolean(true)))   // true

Type Guard Usage

typescript
import { isObject } from 'radash'

function processValue(value: unknown) {
  if (isObject(value)) {
    // TypeScript knows value is an object
    console.log('Processing object:', Object.keys(value))
    return Object.keys(value).length
  }
  
  console.log('Not an object')
  return 0
}

console.log(processValue({ a: 1, b: 2 }))  // Processing object: ['a', 'b'] 2
console.log(processValue([1, 2, 3]))       // Processing object: ['0', '1', '2'] 3
console.log(processValue('hello'))          // Not an object 0

Array Filtering

typescript
import { isObject } from 'radash'

const mixedArray = [
  { name: 'Alice' },
  [1, 2, 3],
  'hello',
  123,
  new Date(),
  null,
  undefined,
  () => {}
]

const objects = mixedArray.filter(isObject)
console.log(objects.length) // 3

const nonObjects = mixedArray.filter(item => !isObject(item))
console.log(nonObjects.length) // 5

Object Property Checking

typescript
import { isObject } from 'radash'

const data = {
  user: { name: 'Alice', age: 25 },
  settings: { theme: 'dark', notifications: true },
  items: [1, 2, 3],
  count: 5,
  name: 'test',
  isActive: true
}

const objectProperties = Object.entries(data)
  .filter(([key, value]) => isObject(value))
  .map(([key, value]) => ({ key, type: Array.isArray(value) ? 'array' : 'object' }))

console.log(objectProperties)
// [
//   { key: 'user', type: 'object' },
//   { key: 'settings', type: 'object' },
//   { key: 'items', type: 'array' }
// ]

Deep Object Checking

typescript
import { isObject } from 'radash'

function getObjectPaths(obj: any, path = ''): string[] {
  const paths: string[] = []
  
  if (!isObject(obj)) {
    return paths
  }
  
  Object.keys(obj).forEach(key => {
    const currentPath = path ? `${path}.${key}` : key
    paths.push(currentPath)
    
    if (isObject(obj[key])) {
      paths.push(...getObjectPaths(obj[key], currentPath))
    }
  })
  
  return paths
}

const nestedObject = {
  user: {
    profile: {
      name: 'Alice',
      settings: {
        theme: 'dark'
      }
    }
  },
  data: [1, 2, 3]
}

console.log(getObjectPaths(nestedObject))
// ['user', 'user.profile', 'user.profile.name', 'user.profile.settings', 'user.profile.settings.theme', 'data']

API Response Processing

typescript
import { isObject } from 'radash'

interface ApiResponse {
  data: unknown
  meta: unknown
  errors: unknown
}

function processApiResponse(response: ApiResponse) {
  const processed = {
    data: isObject(response.data) ? response.data : {},
    meta: isObject(response.meta) ? response.meta : {},
    errors: isObject(response.errors) ? response.errors : {}
  }
  
  return processed
}

const response1: ApiResponse = {
  data: { id: 1, name: 'Alice' },
  meta: { total: 1, page: 1 },
  errors: null
}

const response2: ApiResponse = {
  data: 'not an object',
  meta: 123,
  errors: 'error string'
}

console.log(processApiResponse(response1))
// { data: { id: 1, name: 'Alice' }, meta: { total: 1, page: 1 }, errors: {} }

console.log(processApiResponse(response2))
// { data: {}, meta: {}, errors: {} }

Configuration Validation

typescript
import { isObject } from 'radash'

interface Config {
  server: unknown
  database: unknown
  api: unknown
}

function validateConfig(config: Config) {
  const errors: string[] = []
  
  if (!isObject(config.server)) {
    errors.push('server must be an object')
  }
  
  if (!isObject(config.database)) {
    errors.push('database must be an object')
  }
  
  if (!isObject(config.api)) {
    errors.push('api must be an object')
  }
  
  return errors
}

const validConfig: Config = {
  server: { port: 3000, host: 'localhost' },
  database: { url: 'postgresql://localhost:5432/mydb' },
  api: { version: 'v1', timeout: 5000 }
}

const invalidConfig: Config = {
  server: 'localhost:3000',
  database: null,
  api: undefined
}

console.log(validateConfig(validConfig))   // []
console.log(validateConfig(invalidConfig)) // ['server must be an object', 'database must be an object', 'api must be an object']

Form Data Processing

typescript
import { isObject } from 'radash'

interface FormData {
  personalInfo: unknown
  address: unknown
  preferences: unknown
}

function validateFormData(data: FormData) {
  const errors: string[] = []
  
  if (!isObject(data.personalInfo)) {
    errors.push('personalInfo must be an object')
  }
  
  if (!isObject(data.address)) {
    errors.push('address must be an object')
  }
  
  if (!isObject(data.preferences)) {
    errors.push('preferences must be an object')
  }
  
  return errors
}

const validFormData: FormData = {
  personalInfo: { name: 'Alice', age: 25 },
  address: { street: '123 Main St', city: 'Beijing' },
  preferences: { theme: 'dark', notifications: true }
}

const invalidFormData: FormData = {
  personalInfo: 'Alice',
  address: null,
  preferences: undefined
}

console.log(validateFormData(validFormData))   // []
console.log(validateFormData(invalidFormData)) // ['personalInfo must be an object', 'address must be an object', 'preferences must be an object']

Database Record Processing

typescript
import { isObject } from 'radash'

interface DatabaseRecord {
  id: number
  data: unknown
  metadata: unknown
  settings: unknown
}

function sanitizeDatabaseRecord(record: DatabaseRecord) {
  return {
    id: record.id,
    data: isObject(record.data) ? record.data : {},
    metadata: isObject(record.metadata) ? record.metadata : {},
    settings: isObject(record.settings) ? record.settings : {}
  }
}

const dbRecord: DatabaseRecord = {
  id: 1,
  data: { name: 'Product A', price: 29.99 },
  metadata: { created: new Date(), updated: new Date() },
  settings: null
}

console.log(sanitizeDatabaseRecord(dbRecord))
// { id: 1, data: { name: 'Product A', price: 29.99 }, metadata: { created: Date, updated: Date }, settings: {} }

Event Object Processing

typescript
import { isObject } from 'radash'

interface EventData {
  target: unknown
  data: unknown
  context: unknown
}

function processEvent(event: EventData) {
  const processed = {
    target: isObject(event.target) ? event.target : {},
    data: isObject(event.data) ? event.data : {},
    context: isObject(event.context) ? event.context : {}
  }
  
  return processed
}

const event: EventData = {
  target: { id: 'button1', type: 'button' },
  data: { x: 100, y: 200 },
  context: null
}

console.log(processEvent(event))
// { target: { id: 'button1', type: 'button' }, data: { x: 100, y: 200 }, context: {} }

Nested Object Validation

typescript
import { isObject } from 'radash'

function validateNestedObject(obj: unknown, maxDepth = 5, currentDepth = 0): boolean {
  if (currentDepth > maxDepth) {
    return false
  }
  
  if (!isObject(obj)) {
    return true
  }
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (!validateNestedObject(obj[key], maxDepth, currentDepth + 1)) {
        return false
      }
    }
  }
  
  return true
}

const validNestedObject = {
  level1: {
    level2: {
      level3: {
        value: 'deep'
      }
    }
  }
}

const invalidNestedObject = {
  level1: {
    level2: {
      level3: {
        level4: {
          level5: {
            level6: {
              value: 'too deep'
            }
          }
        }
      }
    }
  }
}

console.log(validateNestedObject(validNestedObject))     // true
console.log(validateNestedObject(invalidNestedObject))   // false

Object Merging

typescript
import { isObject } from 'radash'

function deepMerge(target: any, source: any): any {
  if (!isObject(target) || !isObject(source)) {
    return source
  }
  
  const result = { ...target }
  
  for (const key in source) {
    if (source.hasOwnProperty(key)) {
      if (isObject(source[key]) && isObject(target[key])) {
        result[key] = deepMerge(target[key], source[key])
      } else {
        result[key] = source[key]
      }
    }
  }
  
  return result
}

const obj1 = {
  user: {
    name: 'Alice',
    settings: {
      theme: 'dark'
    }
  },
  data: [1, 2, 3]
}

const obj2 = {
  user: {
    age: 25,
    settings: {
      notifications: true
    }
  },
  data: [4, 5, 6]
}

console.log(deepMerge(obj1, obj2))
// {
//   user: {
//     name: 'Alice',
//     age: 25,
//     settings: {
//       theme: 'dark',
//       notifications: true
//     }
//   },
//   data: [4, 5, 6]
// }

Object Comparison

typescript
import { isObject } from 'radash'

function deepEqual(a: unknown, b: unknown): boolean {
  if (a === b) {
    return true
  }
  
  if (!isObject(a) || !isObject(b)) {
    return false
  }
  
  const keysA = Object.keys(a)
  const keysB = Object.keys(b)
  
  if (keysA.length !== keysB.length) {
    return false
  }
  
  for (const key of keysA) {
    if (!keysB.includes(key)) {
      return false
    }
    
    if (!deepEqual(a[key], b[key])) {
      return false
    }
  }
  
  return true
}

const obj1 = { a: 1, b: { c: 2, d: 3 } }
const obj2 = { a: 1, b: { c: 2, d: 3 } }
const obj3 = { a: 1, b: { c: 2, d: 4 } }

console.log(deepEqual(obj1, obj2)) // true
console.log(deepEqual(obj1, obj3)) // false

Object Serialization

typescript
import { isObject } from 'radash'

function safeStringify(obj: unknown): string {
  if (!isObject(obj)) {
    return JSON.stringify(obj)
  }
  
  const seen = new WeakSet()
  
  return JSON.stringify(obj, (key, value) => {
    if (isObject(value)) {
      if (seen.has(value)) {
        return '[Circular Reference]'
      }
      seen.add(value)
    }
    return value
  })
}

const circularObj: any = {
  name: 'Alice',
  data: { id: 1 }
}
circularObj.self = circularObj

console.log(safeStringify(circularObj))
// {"name":"Alice","data":{"id":1},"self":"[Circular Reference]"}

Object Cloning

typescript
import { isObject } from 'radash'

function deepClone(obj: unknown): unknown {
  if (!isObject(obj)) {
    return obj
  }
  
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item))
  }
  
  const cloned: any = {}
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key])
    }
  }
  
  return cloned
}

const original = {
  name: 'Alice',
  age: 25,
  hobbies: ['reading', 'coding'],
  address: {
    street: '123 Main St',
    city: 'Beijing'
  }
}

const cloned = deepClone(original)
console.log(cloned)
// { name: 'Alice', age: 25, hobbies: ['reading', 'coding'], address: { street: '123 Main St', city: 'Beijing' } }

// Verify it's a deep copy
original.address.city = 'Shanghai'
console.log(cloned.address.city) // 'Beijing'

Notes

  1. Object Definition: Checks all object types, including arrays, Date, RegExp, etc.
  2. Null Check: null is not considered an object
  3. Function Check: Functions are not considered objects
  4. Type Guards: Serves as a TypeScript type guard
  5. Performance: Fast checking, suitable for high-frequency use

Differences from Other Methods

  • isObject(): Checks if value is an object
  • typeof value === 'object': Native JavaScript check (includes null)
  • value !== null && typeof value === 'object': Object check excluding null
  • Array.isArray(): Checks if value is an array

Practical Application Scenarios

  1. Data Validation: Validate object fields in API responses
  2. Configuration Processing: Validate configuration objects
  3. Form Processing: Validate form data objects
  4. Database Operations: Validate database record objects
  5. Event Handling: Validate event objects
  6. Object Operations: Deep object operations and comparisons

Released under the MIT License.