Symbol.observable ponyfill for consistent observable symbol usage across JavaScript environments
npx @tessl/cli install tessl/npm-symbol-observable@4.0.0Symbol.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.
npm install symbol-observableimport 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;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"symbol-observable implements a ponyfill strategy with environment detection:
The package ensures all observable libraries use the same symbol reference, preventing interoperability issues.
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:
Symbol.for('https://github.com/benlesh/symbol-observable')Symbol('https://github.com/benlesh/symbol-observable')'@@observable'The symbol is automatically assigned to Symbol.observable when possible, ensuring ecosystem compatibility.
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:
Returns:
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';
}// 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;
}'@@observable' string identifierThe 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.