or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# symbol-observable

1

2

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.

3

4

## Package Information

5

6

- **Package Name**: symbol-observable

7

- **Package Type**: npm

8

- **Language**: JavaScript (with TypeScript support)

9

- **Installation**: `npm install symbol-observable`

10

11

## Core Imports

12

13

```typescript

14

import symbolObservable from "symbol-observable";

15

```

16

17

```javascript

18

// CommonJS

19

const symbolObservable = require("symbol-observable").default;

20

```

21

22

For ponyfill function:

23

24

```typescript

25

import makeObservableSymbol from "symbol-observable/ponyfill";

26

```

27

28

```javascript

29

// CommonJS

30

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

31

```

32

33

## Basic Usage

34

35

```typescript

36

import symbolObservable from "symbol-observable";

37

38

// Use the observable symbol to make objects observable

39

const myObservable = {

40

[symbolObservable]() {

41

return {

42

subscribe(observer) {

43

// Implementation

44

const handler = (data) => observer.next(data);

45

46

// Setup data source

47

someDataSource.addEventListener('data', handler);

48

49

return {

50

unsubscribe() {

51

someDataSource.removeEventListener('data', handler);

52

}

53

};

54

},

55

[symbolObservable]() {

56

return this;

57

}

58

};

59

}

60

};

61

62

// The symbol works consistently across different environments

63

console.log(typeof symbolObservable); // "symbol" in modern environments, "string" in legacy environments

64

console.log(symbolObservable); // Symbol(https://github.com/benlesh/symbol-observable) or "@@observable"

65

```

66

67

## Architecture

68

69

symbol-observable implements a ponyfill strategy with environment detection:

70

71

- **Symbol Detection**: Detects native Symbol support and Symbol.observable availability

72

- **Fallback Strategy**: Uses Symbol.for(), Symbol(), or string fallback based on environment capabilities

73

- **Global Assignment**: Safely attempts to assign Symbol.observable for ecosystem compatibility

74

- **Security Handling**: Gracefully handles frozen Symbol objects in restricted environments

75

76

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

77

78

## Capabilities

79

80

### Observable Symbol Export

81

82

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

83

84

```typescript { .api }

85

/**

86

* The Symbol.observable ponyfill - ensures consistent observable symbol across environments

87

* Returns Symbol.observable if available, otherwise creates appropriate fallback

88

* Runtime type can be either symbol or string depending on environment capabilities

89

*/

90

declare const symbolObservable: symbol | string;

91

export default symbolObservable;

92

93

// Global Symbol augmentation

94

declare global {

95

interface SymbolConstructor {

96

readonly observable: symbol;

97

}

98

}

99

```

100

101

**Environment Behavior:**

102

- **Native Symbol.observable exists**: Returns the existing Symbol.observable

103

- **Symbol.for available**: Creates `Symbol.for('https://github.com/benlesh/symbol-observable')`

104

- **Only Symbol available**: Creates `Symbol('https://github.com/benlesh/symbol-observable')`

105

- **No Symbol support**: Returns string `'@@observable'`

106

107

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

108

109

### Ponyfill Function Export

110

111

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

112

113

```typescript { .api }

114

/**

115

* Creates Symbol.observable ponyfill for the provided root object

116

* @param root - The root/global object to operate on (e.g., window, global, self)

117

* @returns The observable symbol appropriate for the environment

118

* Runtime return type can be either symbol or string depending on environment capabilities

119

*/

120

declare const symbolObservablePonyfill: (root: object) => symbol | string;

121

export default symbolObservablePonyfill;

122

```

123

124

**Parameters:**

125

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

126

127

**Returns:**

128

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

129

130

**Usage Example:**

131

132

```typescript

133

import makeObservableSymbol from "symbol-observable/ponyfill";

134

135

// Use with custom root object

136

const customRoot = { Symbol: MyCustomSymbolImplementation };

137

const observableSymbol = makeObservableSymbol(customRoot);

138

console.log(typeof observableSymbol); // "symbol" or "string" depending on customRoot.Symbol

139

140

// Use with current global

141

const globalSymbol = makeObservableSymbol(

142

typeof window !== 'undefined' ? window : global

143

);

144

145

// Handle both symbol and string cases in your code

146

function isObservable(obj: any): boolean {

147

return obj != null && typeof obj[globalSymbol] === 'function';

148

}

149

```

150

151

## Types

152

153

```typescript { .api }

154

// Main export type - actual runtime type varies by environment

155

type ObservableSymbol = symbol | string;

156

157

// Ponyfill function signature - returns symbol in modern environments, string in legacy

158

type SymbolObservablePonyfill = (root: object) => symbol | string;

159

160

// Observable interface (for reference - not exported by this package)

161

interface Observable<T> {

162

subscribe(observer: Observer<T>): Subscription;

163

[Symbol.observable](): Observable<T>;

164

}

165

166

interface Observer<T> {

167

next(value: T): void;

168

error?(error: any): void;

169

complete?(): void;

170

}

171

172

interface Subscription {

173

unsubscribe(): void;

174

}

175

```

176

177

## Environment Compatibility

178

179

### JavaScript Environments

180

- **Node.js**: All versions (falls back to string in very old versions without Symbol)

181

- **Browsers**: Modern browsers with Symbol support use native symbols

182

- **Legacy Browsers**: Automatic fallback to `'@@observable'` string identifier

183

- **Web Workers**: Full support with appropriate global detection

184

185

### Module Systems

186

- **ES6 Modules**: Native import/export support

187

- **CommonJS**: Compatible with require() and module.exports

188

- **TypeScript**: Full type definitions included

189

- **UMD**: Works in browser script tags and AMD loaders

190

191

### Security Considerations

192

- **Frozen Symbol**: Gracefully handles frozen Symbol objects in security-restricted environments

193

- **CSP Compliance**: No eval() or unsafe dynamic code execution

194

- **Immutable**: Package only reads from globals, never modifies them unsafely

195

196

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.