JSPM

@avstantso/js

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

JavaScript helpers

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/js) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    @avstantso/js

    npm version License: MIT

    JavaScript runtime type checking and manipulation utilities for robust type-safe JavaScript operations.

    Features

    • Type checking utilities - Type-safe wrappers for typeof and instanceof with convenient shortcuts
    • Switch by type - Pattern matching based on runtime type with support for null and default cases
    • Runtime type information - Attach and query type metadata to objects and functions
    • Set membership testing - Check if values belong to specific sets with type safety
    • Structure detection - Identify objects that can be used with Object.defineProperty
    • Zero dependencies beyond the monorepo packages

    Installation

    npm install @avstantso/js

    or

    yarn add @avstantso/js

    Usage

    Global Access

    Import the package to register the AVStantso.JS namespace globally:

    import '@avstantso/js';
    
    // Use utilities from the global namespace
    if (AVStantso.JS.is.string(value)) {
      console.log(value.toUpperCase());
    }

    Direct Member Imports

    Import the JS namespace directly for cleaner code:

    import { JS } from '@avstantso/js';
    
    // Use imported JS namespace
    if (JS.is.string(value)) {
      console.log(value.toUpperCase());
    }
    
    // Pattern matching on types
    const result = JS.switch(data, {
      string: (s) => s.length,
      number: (n) => n * 2,
      default: () => 0
    });

    Exported Members:

    • JS - Complete JavaScript utilities namespace (same as AVStantso.JS)

    API Reference

    JS.Type

    Union type of all JavaScript types (possible results of typeof operator).

    Type Definition:

    type Type = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function'

    JS.Types

    Readonly map of JavaScript type names to themselves. Useful for type-safe comparisons.

    Example:

    import { JS } from '@avstantso/js';
    
    console.log(JS.Types.string); // 'string'
    console.log(JS.Types.number); // 'number'
    
    // Use in comparisons
    const type = typeof value;
    if (type === JS.Types.string) {
      // Type-safe string handling
    }

    JS.is

    Type-safe wrapper for typeof and instanceof checks with convenient shortcuts.

    JS.is(type, candidate)

    Check if candidate is of the specified type.

    Parameters:

    • type - JavaScript type to check for ('string', 'number', etc.)
    • candidate - Value to test

    Returns: Type predicate candidate is T

    Example:

    import { JS } from '@avstantso/js';
    
    const value: unknown = 'hello';
    
    if (JS.is('string', value)) {
      // TypeScript knows value is string here
      console.log(value.toUpperCase());
    }
    
    if (JS.is('number', value)) {
      // TypeScript knows value is number here
      console.log(value.toFixed(2));
    }

    Type Shortcuts

    Convenient shortcuts for common type checks. All shortcuts provide type narrowing.

    JS.is.string(candidate)

    Check if candidate is a string.

    Example:

    import { JS } from '@avstantso/js';
    
    if (JS.is.string(value)) {
      console.log(value.toUpperCase()); // TypeScript knows value is string
    }

    JS.is.number(candidate)

    Check if candidate is a number.

    Example:

    import { JS } from '@avstantso/js';
    
    if (JS.is.number(value)) {
      console.log(value.toFixed(2)); // TypeScript knows value is number
    }

    JS.is.bigint(candidate)

    Check if candidate is a bigint.

    JS.is.boolean(candidate)

    Check if candidate is a boolean.

    JS.is.symbol(candidate)

    Check if candidate is a symbol.

    JS.is.undefined(candidate)

    Check if candidate is undefined.

    JS.is.object(candidate)

    Check if candidate is an object (including null).

    Note: Remember that typeof null === 'object' in JavaScript.

    JS.is.function(candidate)

    Check if candidate is a function.

    Example:

    import { JS } from '@avstantso/js';
    
    if (JS.is.function(value)) {
      const result = value(); // TypeScript knows value is a function
    }

    JS.is.class(objClass, candidate)

    Check if candidate is an instance of the specified class.

    Parameters:

    • objClass - Class constructor to check against
    • candidate - Value to test

    Returns: Type predicate candidate is T

    Example:

    import { JS } from '@avstantso/js';
    
    class User {
      constructor(public name: string) {}
    }
    
    const value: unknown = new User('John');
    
    if (JS.is.class(User, value)) {
      // TypeScript knows value is User here
      console.log(value.name);
    }
    
    // Works with built-in classes too
    if (JS.is.class(Date, value)) {
      console.log(value.getTime());
    }
    
    if (JS.is.class(Array, value)) {
      console.log(value.length);
    }

    JS.is.error(errClass, candidate)

    Check if candidate is an instance of the specified Error class.

    Parameters:

    • errClass - Error class constructor to check against
    • candidate - Value to test

    Returns: Type predicate candidate is T extends Error

    Example:

    import { JS } from '@avstantso/js';
    
    class ValidationError extends Error {
      constructor(public field: string, message: string) {
        super(message);
      }
    }
    
    try {
      throw new ValidationError('email', 'Invalid email format');
    } catch (err) {
      if (JS.is.error(ValidationError, err)) {
        // TypeScript knows err is ValidationError
        console.log(`Field ${err.field}: ${err.message}`);
      } else if (JS.is.error(Error, err)) {
        // TypeScript knows err is Error
        console.log(err.message);
      }
    }

    JS.is.structure(candidate)

    Check if candidate is a structure type (object or function) that can be used with Object.defineProperty.

    Returns: Type predicate candidate is object | Function

    Example:

    import { JS } from '@avstantso/js';
    
    function attachMetadata(target: unknown, key: string, value: any) {
      if (JS.is.structure(target)) {
        // TypeScript knows target is object | Function
        Object.defineProperty(target, key, { value, enumerable: false });
      }
    }
    
    const obj = {};
    attachMetadata(obj, 'version', '1.0.0');
    
    const func = () => {};
    attachMetadata(func, 'description', 'My function');
    
    attachMetadata('string', 'prop', 'value'); // Does nothing - strings aren't structures

    JS.is.oneOf

    Check if a candidate is of a specific type AND is a member of a given set.

    JS.is.oneOf(type, candidate, ...set)

    Check if candidate is of the specified type and is included in the set.

    Parameters:

    • type - JavaScript type to check for
    • candidate - Value to test
    • ...set - Values to check membership against (can be array, Set, or spread arguments)

    Returns: Type predicate candidate is T

    Example:

    import { JS } from '@avstantso/js';
    
    const value: unknown = 'admin';
    
    // Check if string and in allowed set
    if (JS.is.oneOf('string', value, 'admin', 'user', 'guest')) {
      console.log(`Valid role: ${value}`);
    }
    
    // Using an array
    const validRoles = ['admin', 'user', 'guest'];
    if (JS.is.oneOf('string', value, validRoles)) {
      console.log(`Valid role: ${value}`);
    }
    
    // Using a Set
    const validNumbers = new Set([1, 2, 3, 5, 8, 13]);
    if (JS.is.oneOf('number', value, validNumbers)) {
      console.log(`Fibonacci number: ${value}`);
    }

    Type Shortcuts for oneOf

    All shortcuts work the same way, checking both type and set membership.

    JS.is.oneOf.string(candidate, ...set)

    Check if candidate is a string in the given set.

    Example:

    import { JS } from '@avstantso/js';
    
    type Status = 'pending' | 'active' | 'completed';
    
    function processStatus(status: unknown) {
      if (JS.is.oneOf.string(status, 'pending', 'active', 'completed')) {
        // TypeScript knows status is string and one of the valid values
        console.log(`Processing ${status} status`);
      }
    }

    JS.is.oneOf.number(candidate, ...set)

    Check if candidate is a number in the given set.

    Example:

    import { JS } from '@avstantso/js';
    
    const validPorts = [80, 443, 8080, 3000];
    
    if (JS.is.oneOf.number(port, validPorts)) {
      console.log(`Valid port: ${port}`);
    }

    JS.is.oneOf.bigint(candidate, ...set)

    Check if candidate is a bigint in the given set.

    JS.is.oneOf.boolean(candidate, ...set)

    Check if candidate is a boolean in the given set.

    JS.is.oneOf.symbol(candidate, ...set)

    Check if candidate is a symbol in the given set.

    JS.is.oneOf.undefined(candidate, ...set)

    Check if candidate is undefined in the given set.

    JS.is.oneOf.object(candidate, ...set)

    Check if candidate is an object in the given set.

    JS.is.oneOf.function(candidate, ...set)

    Check if candidate is a function in the given set.

    JS.is.oneOf.class(objClass, candidate, ...set)

    Check if candidate is an instance of the specified class and is in the given set.

    Example:

    import { JS } from '@avstantso/js';
    
    class Admin extends User {}
    class Moderator extends User {}
    
    const validUserClasses = [Admin, Moderator];
    
    if (JS.is.oneOf.class(User, candidate, validUserClasses)) {
      // candidate is either Admin or Moderator instance
    }

    JS.is.oneOf.error(errClass, candidate, ...set)

    Check if candidate is an instance of the specified Error class and is in the given set.

    JS.is.oneOf.structure(candidate, ...set)

    Check if candidate is a structure and is in the given set.


    JS.switch

    Pattern matching utility based on runtime type with support for functions and default cases.

    JS.switch<R>(data, cases)

    Switch on value's runtime type and execute the corresponding case.

    Type Parameters:

    • R - Return type of all cases
    • T - Type of data being switched on (inferred)
    • Cases - Type of cases object (inferred)

    Parameters:

    • data - Value to switch on (uses typeof to determine type)
    • cases - Object mapping type names to handlers or values

    Returns: Result of type R

    Case Keys:

    • JavaScript types: 'string', 'number', 'bigint', 'boolean', 'symbol', 'undefined', 'object', 'function'
    • Special cases: 'null' (checked before typeof), 'default' (fallback when no match)

    Case Values:

    • Static value of type R
    • Function that receives the typed data and returns R

    Basic Usage

    Example:

    import { JS } from '@avstantso/js';
    
    const value: unknown = 42;
    
    const result = JS.switch(value, {
      string: 'It is a string',
      number: 'It is a number',
      boolean: 'It is a boolean',
      default: 'Unknown type'
    });
    
    console.log(result); // 'It is a number'

    Function Handlers

    Example:

    import { JS } from '@avstantso/js';
    
    const value: unknown = 'hello';
    
    const result = JS.switch(value, {
      string: (s) => s.toUpperCase(),
      number: (n) => n * 2,
      boolean: (b) => !b,
      default: () => null
    });
    
    console.log(result); // 'HELLO'

    Null Handling

    The null case is checked before typeof, allowing you to distinguish null from other objects.

    Example:

    import { JS } from '@avstantso/js';
    
    const value: unknown = null;
    
    const result = JS.switch(value, {
      null: 'Explicitly null',
      object: 'Some object',
      default: 'Other type'
    });
    
    console.log(result); // 'Explicitly null'

    Complex Example

    Example:

    import { JS } from '@avstantso/js';
    
    function formatValue(value: unknown): string {
      return JS.switch(value, {
        string: (s) => `"${s}"`,
        number: (n) => n.toFixed(2),
        boolean: (b) => b ? 'YES' : 'NO',
        null: 'NULL',
        undefined: 'UNDEFINED',
        object: (o) => {
          if (Array.isArray(o)) return `[Array: ${o.length} items]`;
          if (o instanceof Date) return o.toISOString();
          return '[Object]';
        },
        function: (f) => `[Function: ${f.name || 'anonymous'}]`,
        default: () => '[Unknown]'
      });
    }
    
    console.log(formatValue('hello'));          // "hello"
    console.log(formatValue(42.5));             // 42.50
    console.log(formatValue(true));             // YES
    console.log(formatValue(null));             // NULL
    console.log(formatValue(undefined));        // UNDEFINED
    console.log(formatValue([1, 2, 3]));        // [Array: 3 items]
    console.log(formatValue(new Date()));       // 2024-01-09T12:00:00.000Z
    console.log(formatValue(() => {}));         // [Function: anonymous]

    Type Inference

    The return type is inferred from the cases:

    Example:

    import { JS } from '@avstantso/js';
    
    // Return type inferred as number
    const num = JS.switch(value, {
      string: 1,
      number: 2,
      default: 0
    });
    
    // Return type inferred as string | number
    const mixed = JS.switch(value, {
      string: 'text',
      number: 42,
      default: 0
    });

    JS.TypeInfo

    Runtime type information system for attaching metadata to objects and functions.

    JS.TypeInfo

    Type definition for runtime type information metadata.

    Type Definition:

    type TypeInfo = NodeJS.ReadOnlyDict<TS.Literal>

    Description: Runtime type information map where keys are property names and values are type literal strings ('string', 'number', etc.).

    This is useful for scenarios like:

    • Dynamic component rendering
    • Form field type inference
    • API schema validation
    • Automatic serialization/deserialization

    Example:

    import { JS } from '@avstantso/js';
    
    const userTypeInfo: JS.TypeInfo = {
      id: 'number',
      name: 'string',
      email: 'string',
      active: 'boolean',
      createdAt: 'Date'
    };

    JS.TypeInfo.Provider

    Interface for objects that provide runtime type information.

    Type Definition:

    interface Provider {
      typeInfo: TypeInfo;
    }

    Example:

    import { JS } from '@avstantso/js';
    
    class User implements JS.TypeInfo.Provider {
      typeInfo = {
        id: 'number',
        name: 'string',
        email: 'string',
        active: 'boolean'
      } as const;
    
      constructor(
        public id: number,
        public name: string,
        public email: string,
        public active: boolean
      ) {}
    }
    
    const user = new User(1, 'John', 'john@example.com', true);
    console.log(user.typeInfo); // { id: 'number', name: 'string', ... }

    JS.hasTypeInfo(candidate)

    Check if a value has attached type information.

    Parameters:

    • candidate - Value to check

    Returns: Type predicate candidate is TypeInfo.Provider

    Example:

    import { JS } from '@avstantso/js';
    
    class Component {
      typeInfo = { label: 'string', value: 'number' };
    }
    
    const obj1 = new Component();
    const obj2 = { data: 'test' };
    
    if (JS.hasTypeInfo(obj1)) {
      // TypeScript knows obj1 has typeInfo property
      console.log(obj1.typeInfo); // { label: 'string', value: 'number' }
    }
    
    if (JS.hasTypeInfo(obj2)) {
      // This won't execute
      console.log(obj2.typeInfo);
    }

    JS.tryTypeInfo(candidate)

    Attempt to retrieve type information from a value.

    Parameters:

    • candidate - Value to extract type info from

    Returns: TypeInfo if available, false otherwise

    Example:

    import { JS } from '@avstantso/js';
    
    function renderField(html: string) {
      const [component, data] = /* parse html to determine component and attributes */;
      const typeInfo = JS.tryTypeInfo(component);
    
      if (typeInfo) {
        // Use type information to render appropriately
        for (const [field, type] of Object.entries(typeInfo)) {
          const value = data[field];
    
          if (type === 'boolean' && value === undefined) {
            // Interpret key without value boolean as true
            data[field] = true;
          }
        }
      }
    
      return [component, data];
    }
    
    // Example: React component with type info
    const InputField = {
      typeInfo: {
        label: 'string',
        required: 'boolean',
        maxLength: 'number'
      },
      render: (props: any) => { /* ... */ }
    };
    
    const [Component, props] = renderField('<InputField label="Email" maxLength=50 required />');
    // props result: { label: 'Email', maxLength: 50, required: true }
    Component.render(props);

    Use Case: Dynamic Form Rendering

    Example:

    import { JS } from '@avstantso/js';
    
    interface FieldConfig {
      typeInfo: JS.TypeInfo;
      label: string;
      name: string;
    }
    
    function createField(config: FieldConfig) {
      const { typeInfo, label, name } = config;
    
      return {
        ...config,
        validate: (value: unknown) => {
          const expectedType = typeInfo[name];
          return JS.is(expectedType as any, value);
        },
        render: () => {
          // Render input based on type
          const type = typeInfo[name];
          switch (type) {
            case 'string': return `<input type="text" name="${name}" />`;
            case 'number': return `<input type="number" name="${name}" />`;
            case 'boolean': return `<input type="checkbox" name="${name}" />`;
            default: return `<input name="${name}" />`;
          }
        }
      };
    }
    
    const emailField = createField({
      typeInfo: { email: 'string' },
      label: 'Email',
      name: 'email'
    });
    
    console.log(emailField.validate('test@example.com')); // true
    console.log(emailField.validate(123)); // false

    Requirements

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

    Dependencies

    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.