JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 786
  • Score
    100M100P100Q96780F
  • License MIT

Fast and lightweight utility functions to check if a value is a plain object.

Package Exports

  • @httpx/plain-object
  • @httpx/plain-object/package.json

Readme

@httpx/plain-object

Fast and lightweight (~100B) functions to check or assert that a value is a plain object.

npm changelog codecov bundles node browserslist size downloads license

Install

$ npm install @httpx/plain-object
$ yarn add @httpx/plain-object
$ pnpm add @httpx/plain-object

Features

Documentation

πŸ‘‰ Official website or Github Readme

Usage

isPlainObject

import { isPlainObject } from '@httpx/plain-object';

// βœ…πŸ‘‡ True

isPlainObject({ key: 'value' });          // βœ… 
isPlainObject({ key: new Date() });       // βœ… 
isPlainObject(new Object());              // βœ… 
isPlainObject(Object.create(null));       // βœ… 
isPlainObject({ nested: { key: true} });  // βœ… 
isPlainObject(new Proxy({}, {}));         // βœ… 
isPlainObject({ [Symbol('tag')]: 'A' });  // βœ… 

// βœ…πŸ‘‡ (node context, workers, ...)
const runInNewContext = await import('node:vm').then(
    (mod) => mod.runInNewContext
);
isPlainObject(runInNewContext('({})'));   // βœ… 

// βŒπŸ‘‡ False

class Test { };
isPlainObject(new Test())           // ❌ 
isPlainObject(10);                  // ❌ 
isPlainObject(null);                // ❌ 
isPlainObject('hello');             // ❌ 
isPlainObject([]);                  // ❌ 
isPlainObject(new Date());          // ❌ 
isPlainObject(Math);                // ❌ Static built-in classes 
isPlainObject(Promise.resolve({})); // ❌
isPlainObject(Object.create({}));   // ❌

assertPlainObject

import { assertPlainObject } from '@httpx/plain-object';
import type { PlainObject } from '@httpx/plain-object';

function fn(value: unknown) {

    // πŸ‘‡ Throws `new TypeError('Not a plain object')` if not a plain object
    assertPlainObject(value);

    // πŸ‘‡ Throws `new TypeError('Custom message')` if not a plain object
    assertPlainObject(value, 'Custom message');

    // πŸ‘‡ Throws custom error if not a plain object
    assertPlainObject(value, () => {
        throw new HttpBadRequest('Custom message');
    });
    
    return value;
}

try {
    const value = fn({ key: 'value' });
    // βœ… Value is known to be PlainObject<unknown>
    assertType<PlainObject>(value);
} catch (error) {
    console.error(error);
}

PlainObject type

Generic

Γ¬sPlainObject and assertPlainObject accepts a generic to provide type autocompletion. Be aware that no runtime check are done. If you're looking for runtime validation, check zod, valibot or other alternatives.

import { isPlainObject } from '@httpx/plain-object';
import type { PlainObject } from '@httpx/plain-object';

type CustomType = {
    id: number;
    data?: {
        test: string[];
        attributes?: {
            url?: string | null;
            caption?: string | null;
            alternativeText?: string | null;
        } | null;
    } | null;
};

const value = { id: 1 } as unknown;

if (isPlainObject<CustomType>(value)) {
   // βœ… Value is a PlainObject with typescript autocompletion
   // Note that there's no runtime checking of keys, so they are
   // `unknown | undefined`. They will require unsing `?.` to access. 
    
  const url = value?.data?.attributes?.url; // autocompletion works
  // βœ… url is `unknown | undefined`, so in order to use it, you'll need to
  //    manually check for the type.
  if (typeof url === 'string') {
      console.log(url.toUpperCase());
  }
}

PlainObject

import { assertPlainObject } from '@httpx/plain-object';
import type { PlainObject } from '@httpx/plain-object';

function someFn(value: PlainObject) {
  //    
}

const value = { key: 'value' } as unknown;
assertPlainObject(value);
someFn(value)

Benchmarks

Performance is continuously monitored thanks to codspeed.io.

CodSpeed Badge

 RUN  v2.1.2 /home/sebastien/github/httpx/packages/plain-object

 βœ“ bench/comparative.bench.ts (6) 4398ms
   βœ“ Compare calling isPlainObject with 100x mixed types values (6) 4396ms
     name                                                         hz     min      max    mean     p75     p99    p995    p999     rme  samples      
   Β· @httpx/plain-object: `isPlainObject(v)`              870,872.90  0.0009   8.7832  0.0011  0.0010  0.0019  0.0021  0.0068  Β±4.74%   435437   fastest
   Β· (sindresorhus/)is-plain-obj: `isPlainObj(v)`         847,061.21  0.0009   6.4363  0.0012  0.0010  0.0019  0.0020  0.0088  Β±5.07%   423531      
   Β· @sindresorhus/is: `is.plainObject(v)`                515,510.42  0.0015  11.1225  0.0019  0.0017  0.0030  0.0032  0.0092  Β±7.23%   257756      
   Β· estoolkit:  `isPlainObject(v)`                       223,151.78  0.0037   1.5797  0.0045  0.0041  0.0076  0.0090  0.0311  Β±1.21%   111576      
   Β· (jonschlinkert/)is-plain-object: `isPlainObject(v)`  376,177.02  0.0020   8.2668  0.0027  0.0023  0.0039  0.0047  0.0277  Β±4.96%   188089      
   Β· lodash-es: `_.isPlainObject(v)`                       15,546.36  0.0533   6.8019  0.0643  0.0555  0.1326  0.2533  0.6342  Β±3.14%     7774   slowest


 BENCH  Summary

  @httpx/plain-object: `isPlainObject(v)` - bench/comparative.bench.ts > Compare calling isPlainObject with 100x mixed types values
    1.03x faster than (sindresorhus/)is-plain-obj: `isPlainObj(v)`
    1.69x faster than @sindresorhus/is: `is.plainObject(v)`
    2.32x faster than (jonschlinkert/)is-plain-object: `isPlainObject(v)`
    3.90x faster than estoolkit:  `isPlainObject(v)`
    56.02x faster than lodash-es: `_.isPlainObject(v)`

See benchmark file for details.

Bundle size

Bundle size is tracked by a size-limit configuration

Scenario (esm) Size (compressed)
import { isPlainObject } from '@httpx/plain-object ~ 101B
import { assertPlainObject } from '@httpx/plain-object ~ 165B
isPlainObject + assertPlainObject ~ 165B

For CJS usage (not recommended) track the size on bundlephobia.

Compatibility

Level CI Description
Node βœ… CI for 18.x, 20.x & 22.x.
Browsers βœ… > 96% on 07/2024. Mins to Chrome 96+, Firefox 90+, Edge 19+, iOS 12+, Safari 12+, Opera 77+
Edge βœ… Ensured on CI with @vercel/edge-runtime.
Typescript βœ… TS 5.0 + / are-the-type-wrong checks on CI.
ES2022 βœ… Dist files checked with es-check
Performance βœ… Monitored with codspeed.io

For older browsers: most frontend frameworks can transpile the library (ie: nextjs...)

Credits

@sindresorhus/is-plain-obj

This library wouldn't be possible without @sindresorhus is-plain-obj. It passes the same test suite and should be 100% compatible with it. Notable differences:

  • Slighly smaller bundle and performance.
  • Named export.
  • Provide a PlainObject type and assertPlainObject function.
  • Typescript convenience PlainObject type.
  • ESM and CJS formats.

Contributors

Contributions are welcome. Have a look to the CONTRIBUTING document.

Sponsors

If my OSS work brightens your day, let's take it to new heights together! Sponsor, coffee, or star – any gesture of support fuels my passion to improve. Thanks for being awesome! πŸ™β€οΈ

Special thanks to

Jetbrains logo Jetbrains logo
JetBrains Embie.be

License

MIT Β© belgattitude and contributors.