JSPM

@avstantso/std-ext

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

Standard JS objects extension. Zero-dependencies

Package Exports

  • @avstantso/std-ext
  • @avstantso/std-ext/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@avstantso/std-ext) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@avstantso/std-ext

npm version License: MIT

Standard JavaScript objects extension with zero dependencies. Adds useful methods to native String, Array, RegExp, Object, and Symbol with full TypeScript support.

Features

  • Zero dependencies
  • Full TypeScript support with type inference
  • Non-intrusive prototype extensions
  • Useful utility methods for common operations
  • Type-safe array key types for advanced TypeScript usage

Installation

npm install @avstantso/std-ext

or

yarn add @avstantso/std-ext

Usage

Simply import the package once in your application entry point to enable all extensions:

import '@avstantso/std-ext';

// Now all extensions are available
const greeting = "hello".toCapitalized(); // "Hello"
const items = [1, 0, 2, null, 3, false, 4].pack(); // [1, 2, 3, 4]
const escaped = RegExp.escape("file[1].txt"); // "file\\[1\\]\\.txt"

API Reference

RegExp Extensions

RegExp.escape(str)

Escapes all RegExp special characters in a string, making it safe to use in new RegExp(). This is a polyfill for the TC39 RegExp.escape proposal.

Parameters:

  • str: string - The string to escape

Returns: string - New string with escaped RegExp characters

Escaped characters: \ ^ $ . * + ? ( ) [ ] { } |

Example:

RegExp.escape("file[1].txt");     // "file\\[1\\]\\.txt"
RegExp.escape("price: $10.00");   // "price: \\$10\\.00"
RegExp.escape("a+b=c?");          // "a\\+b=c\\?"

// Safe dynamic RegExp creation
const userInput = "test.file[1]";
const regex = new RegExp(RegExp.escape(userInput));
regex.test("test.file[1]"); // true
regex.test("testXfile11");  // false

Object Extensions

Object.definePropertyOnce(o, p, attributes)

Adds a property to an object only if it doesn't already exist. Useful for polyfills and non-intrusive extensions. Especially handy for hot module replacement (HMR) environments like Vite, Webpack, or Parcel where modules may be re-executed multiple times.

Parameters:

  • o: T - Object on which to add the property
  • p: PropertyKey - The property name
  • attributes: PropertyDescriptor - Descriptor for the property

Returns: T - The object passed in

Example:

const obj = { existing: 1 };

Object.definePropertyOnce(obj, 'existing', { value: 999 });
Object.definePropertyOnce(obj, 'newProp', { value: 2 });

console.log(obj.existing); // 1 (unchanged)
console.log(obj.newProp);  // 2 (added)

// Useful for polyfills
Object.definePropertyOnce(String.prototype, 'myMethod', {
  value() { return this.toUpperCase(); }
});

Object.definePropertiesOnce(o, properties)

Adds multiple properties to an object, skipping any that already exist. Same HMR benefits as definePropertyOnce.

Parameters:

  • o: T - Object on which to add the properties
  • properties: PropertyDescriptorMap - Object containing property descriptors

Returns: T - The object passed in

Example:

const obj = { a: 1 };

Object.definePropertiesOnce(obj, {
  a: { value: 999 },  // skipped - already exists
  b: { value: 2 },    // added
  c: { value: 3 }     // added
});

console.log(obj); // { a: 1, b: 2, c: 3 }

Symbol Extensions

Symbol.Has(symb, resultTemplate?)

Creates a type guard function that checks if an object has a specific symbol property. Returns a reusable checker function with proper TypeScript type narrowing.

Parameters:

  • symb: symbol - The symbol to check for
  • resultTemplate?: R - Optional type-only argument to infer the symbol's value type (not used at runtime)

Returns: (obj: unknown) => obj is { [K in Symb]: R } - Type guard function

Example:

const mySymbol = Symbol('mySymbol');
const hasMySymbol = Symbol.Has(mySymbol);

const obj1 = { [mySymbol]: 'value' };
const obj2 = { foo: 'bar' };

hasMySymbol(obj1); // true
hasMySymbol(obj2); // false
hasMySymbol(null); // false (safe with nullish values)

// Works great with well-known symbols
const hasIterator = Symbol.Has(Symbol.iterator);

hasIterator([]);        // true
hasIterator('string');  // true
hasIterator(new Map()); // true
hasIterator({});        // false

// Type narrowing in conditionals
const data: unknown = getExternalData();
if (hasIterator(data)) {
  for (const item of data) { ... } // TypeScript knows data is iterable
}

// With typed value using resultTemplate
const symbolFreeze = Symbol('freeze');
const hasFreeze = Symbol.Has(symbolFreeze, () => {});

if (hasFreeze(obj)) {
  obj[symbolFreeze](); // TypeScript knows it's () => void
}

String Extensions

toCapitalized()

Capitalizes the first character of the string.

Returns: Capitalize<S> where S is the string literal type

Example:

"hello".toCapitalized(); // "Hello"
"world".toCapitalized(); // "World"
"".toCapitalized();      // ""

// Preserves literal types
const a = 'foo' as const;
const b = a.toCapitalized(); // type is 'Foo', not string

toUncapitalized()

Uncapitalizes the first character of the string.

Returns: Uncapitalize<S> where S is the string literal type

Example:

"Hello".toUncapitalized(); // "hello"
"World".toUncapitalized(); // "world"
"".toUncapitalized();      // ""

// Preserves literal types
const a = 'FOO' as const;
const b = a.toUncapitalized(); // type is 'fOO', not string

Array Extensions

pack()

Filters out all falsy values from the array (false, 0, "", null, undefined, NaN).

Returns: New array with only truthy items

Equivalent to: filter((item) => item)

Example:

[1, 0, 2, null, 3, false, 4].pack();           // [1, 2, 3, 4]
["a", "", "b", null, "c"].pack();              // ["a", "b", "c"]
[true, false, true, undefined].pack();         // [true, true]

// Real world example: React conditional CSS classes
function Button({ isActive, isDisabled, isLoading }) {
  return (
    <button
      className={[
        'btn',
        isActive && 'btn--active',
        isDisabled && 'btn--disabled',
        isLoading && 'btn--loading'
      ].pack().join(' ')}
    >
      Click me
    </button>
  );
}

// Compare to the alternative without pack():
function Button({ isActive, isDisabled, isLoading }) {
  return (
    <button
      className={`btn${
        isActive ? ' btn--active' : ''
      }${
        isDisabled ? ' btn--disabled' : ''
      }${
        isLoading ? ' btn--loading' : ''
      }`}
    >
      Click me
    </button>
  );
}

peek()

Returns the last element of the array without modifying it.

Returns: Last item or undefined if array is empty

Equivalent to: at(-1)

Example:

[1, 2, 3, 4].peek();    // 4
["a", "b", "c"].peek(); // "c"
[].peek();              // undefined

TypeScript Advanced Types

The package exports the AVStantso.Array namespace with advanced utility types for working with arrays:

AVStantso.Array.RW<W, T>

Conditional type that selects between Array<T> or ReadonlyArray<T> based on the writable flag.

Type Parameters:

  • W extends boolean - If true, returns Array<T>, otherwise ReadonlyArray<T>
  • T - Array element type (default: unknown)

Example:

type MutableArray = AVStantso.Array.RW<true, number>;    // Array<number>
type ImmutableArray = AVStantso.Array.RW<false, string>; // ReadonlyArray<string>

AVStantso.Array.Key<W>

Gets all valid array method/property keys based on mutability.

Type Parameters:

  • W extends boolean - If true, includes mutation methods; if false, only readonly methods

Example:

type ReadonlyKeys = AVStantso.Array.Key<false>; // Keys like 'map', 'filter', 'length'
type MutableKeys = AVStantso.Array.Key<true>;   // Includes 'push', 'pop', 'splice'

AVStantso.Array.Key namespace

Helper types for array keys:

  • AVStantso.Array.Key.R - Readonly array keys only
  • AVStantso.Array.Key.RW - All array keys (readonly + writable)
  • AVStantso.Array.Key.W - Mutation keys only (writable but not readonly)

Example:

type ReadonlyMethods = AVStantso.Array.Key.R;  // 'map', 'filter', 'forEach', etc.
type AllMethods = AVStantso.Array.Key.RW;      // All array methods
type MutationOnly = AVStantso.Array.Key.W;     // 'push', 'pop', 'splice', etc.

Requirements

  • Node.js 12.0 or higher
  • TypeScript 4.0 or higher (for TypeScript projects)

TypeScript Configuration

To use the type extensions, ensure your tsconfig.json includes the package:

{
  "compilerOptions": {
    "types": ["@avstantso/std-ext"]
  }
}

Or simply import it once in your entry file as shown in the Usage section.

License

MIT - See LICENSE file for details

Repository

GitLab - avstantso-js/cross-platform-utils

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests to the repository.