or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-symbol-observable

Symbol.observable ponyfill for consistent observable symbol usage across JavaScript environments

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/symbol-observable@4.0.x

To install, run

npx @tessl/cli install tessl/npm-symbol-observable@4.0.0

index.mddocs/

symbol-observable

Symbol.observable ponyfill for consistent observable symbol usage across JavaScript environments. This package provides a Symbol.observable implementation that ensures all consumers use the same observable symbol value, which is critical for interoperability between observable libraries like RxJS, XStream, and Most.js.

Package Information

  • Package Name: symbol-observable
  • Package Type: npm
  • Language: JavaScript (with TypeScript support)
  • Installation: npm install symbol-observable

Core Imports

import symbolObservable from "symbol-observable";
// CommonJS
const symbolObservable = require("symbol-observable").default;

For ponyfill function:

import makeObservableSymbol from "symbol-observable/ponyfill";
// CommonJS
const makeObservableSymbol = require("symbol-observable/ponyfill").default;

Basic Usage

import symbolObservable from "symbol-observable";

// Use the observable symbol to make objects observable
const myObservable = {
  [symbolObservable]() {
    return {
      subscribe(observer) {
        // Implementation
        const handler = (data) => observer.next(data);
        
        // Setup data source
        someDataSource.addEventListener('data', handler);
        
        return {
          unsubscribe() {
            someDataSource.removeEventListener('data', handler);
          }
        };
      },
      [symbolObservable]() { 
        return this; 
      }
    };
  }
};

// The symbol works consistently across different environments
console.log(typeof symbolObservable); // "symbol" in modern environments, "string" in legacy environments
console.log(symbolObservable); // Symbol(https://github.com/benlesh/symbol-observable) or "@@observable"

Architecture

symbol-observable implements a ponyfill strategy with environment detection:

  • Symbol Detection: Detects native Symbol support and Symbol.observable availability
  • Fallback Strategy: Uses Symbol.for(), Symbol(), or string fallback based on environment capabilities
  • Global Assignment: Safely attempts to assign Symbol.observable for ecosystem compatibility
  • Security Handling: Gracefully handles frozen Symbol objects in restricted environments

The package ensures all observable libraries use the same symbol reference, preventing interoperability issues.

Capabilities

Observable Symbol Export

Main export providing the Symbol.observable ponyfill that works consistently across all JavaScript environments.

/**
 * The Symbol.observable ponyfill - ensures consistent observable symbol across environments
 * Returns Symbol.observable if available, otherwise creates appropriate fallback
 * Runtime type can be either symbol or string depending on environment capabilities
 */
declare const symbolObservable: symbol | string;
export default symbolObservable;

// Global Symbol augmentation
declare global {
  interface SymbolConstructor {
    readonly observable: symbol;
  }
}

Environment Behavior:

  • Native Symbol.observable exists: Returns the existing Symbol.observable
  • Symbol.for available: Creates Symbol.for('https://github.com/benlesh/symbol-observable')
  • Only Symbol available: Creates Symbol('https://github.com/benlesh/symbol-observable')
  • No Symbol support: Returns string '@@observable'

The symbol is automatically assigned to Symbol.observable when possible, ensuring ecosystem compatibility.

Ponyfill Function Export

Standalone function that creates Symbol.observable for any given root object, useful for custom environments or when you need control over the global assignment.

/**
 * Creates Symbol.observable ponyfill for the provided root object
 * @param root - The root/global object to operate on (e.g., window, global, self)
 * @returns The observable symbol appropriate for the environment
 * Runtime return type can be either symbol or string depending on environment capabilities
 */
declare const symbolObservablePonyfill: (root: object) => symbol | string;
export default symbolObservablePonyfill;

Parameters:

  • root (object): The root/global object to inspect for Symbol support and to assign Symbol.observable if possible

Returns:

  • symbol | string: The observable symbol (if Symbol is supported) or string '@@observable' (in environments without Symbol support)

Usage Example:

import makeObservableSymbol from "symbol-observable/ponyfill";

// Use with custom root object
const customRoot = { Symbol: MyCustomSymbolImplementation };
const observableSymbol = makeObservableSymbol(customRoot);
console.log(typeof observableSymbol); // "symbol" or "string" depending on customRoot.Symbol

// Use with current global
const globalSymbol = makeObservableSymbol(
  typeof window !== 'undefined' ? window : global
);

// Handle both symbol and string cases in your code
function isObservable(obj: any): boolean {
  return obj != null && typeof obj[globalSymbol] === 'function';
}

Types

// Main export type - actual runtime type varies by environment
type ObservableSymbol = symbol | string;

// Ponyfill function signature - returns symbol in modern environments, string in legacy
type SymbolObservablePonyfill = (root: object) => symbol | string;

// Observable interface (for reference - not exported by this package)
interface Observable<T> {
  subscribe(observer: Observer<T>): Subscription;
  [Symbol.observable](): Observable<T>;
}

interface Observer<T> {
  next(value: T): void;
  error?(error: any): void;
  complete?(): void;
}

interface Subscription {
  unsubscribe(): void;
}

Environment Compatibility

JavaScript Environments

  • Node.js: All versions (falls back to string in very old versions without Symbol)
  • Browsers: Modern browsers with Symbol support use native symbols
  • Legacy Browsers: Automatic fallback to '@@observable' string identifier
  • Web Workers: Full support with appropriate global detection

Module Systems

  • ES6 Modules: Native import/export support
  • CommonJS: Compatible with require() and module.exports
  • TypeScript: Full type definitions included
  • UMD: Works in browser script tags and AMD loaders

Security Considerations

  • Frozen Symbol: Gracefully handles frozen Symbol objects in security-restricted environments
  • CSP Compliance: No eval() or unsafe dynamic code execution
  • Immutable: Package only reads from globals, never modifies them unsafely

The ponyfill ensures that all observable-implementing libraries (RxJS, XStream, Most.js, etc.) use the same symbol reference, preventing interoperability issues that could occur if different libraries used different symbols.