JSPM

@avstantso/std-ext

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

Standard JS objects extension. Zero-dependencies

Package Exports

    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.