or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-operations.mdcore.mdindex.mdnested-operations.mdobject-operations.md

core.mddocs/

0

# Core Constructor and Utilities

1

2

Core functionality for creating immutable data structures and utility methods for type checking and configuration.

3

4

## Capabilities

5

6

### Immutable Constructor

7

8

Creates an immutable version of the provided data structure with backwards compatibility.

9

10

```javascript { .api }

11

/**

12

* Creates an immutable version of the provided data structure

13

* @param {*} obj - Data to make immutable (Array, Object, Date, or primitive)

14

* @param {Object} [options] - Configuration options

15

* @param {Object} [options.prototype] - Custom prototype for objects

16

* @param {number} [stackRemaining] - Stack depth limit for circular reference protection (default: 64, development only)

17

* @returns {*} Immutable version of the input

18

*/

19

function Immutable(obj, options, stackRemaining);

20

```

21

22

**Usage Examples:**

23

24

```javascript

25

const Immutable = require("seamless-immutable");

26

27

// Arrays become ImmutableArrays

28

const immutableArray = Immutable([1, 2, 3]);

29

console.log(Array.isArray(immutableArray)); // true - still an array!

30

31

// Objects become ImmutableObjects

32

const immutableObj = Immutable({name: "Alice", age: 30});

33

console.log(typeof immutableObj); // "object"

34

35

// Dates become ImmutableDates

36

const immutableDate = Immutable(new Date());

37

38

// Primitives are returned as-is (already immutable)

39

const str = Immutable("hello"); // Returns "hello"

40

const num = Immutable(42); // Returns 42

41

42

// Custom prototype example

43

function Person(name) {

44

this.name = name;

45

}

46

Person.prototype.greet = function() {

47

return `Hello, I'm ${this.name}`;

48

};

49

50

const person = new Person("Bob");

51

const immutablePerson = Immutable(person, {prototype: Person.prototype});

52

console.log(immutablePerson.greet()); // "Hello, I'm Bob"

53

54

// Stack depth protection (development build only)

55

const deepObject = {};

56

let current = deepObject;

57

for (let i = 0; i < 100; i++) {

58

current.nested = {};

59

current = current.nested;

60

}

61

// Immutable(deepObject); // Would throw ImmutableError after default 64 levels

62

63

// Increase stack limit for legitimately deep (but not circular) objects

64

const allowDeeper = Immutable(deepObject, null, 256); // Allow 256 levels

65

```

66

67

### Immutable.from

68

69

Alias for the main Immutable constructor, provided for linter compatibility.

70

71

```javascript { .api }

72

/**

73

* Alias for Immutable() for linter compatibility (e.g., ESLint new-cap rule)

74

* @param {*} obj - Data to make immutable

75

* @param {Object} [options] - Configuration options

76

* @returns {*} Immutable version of the input

77

*/

78

Immutable.from = Immutable;

79

```

80

81

**Usage Example:**

82

83

```javascript

84

// These are functionally identical

85

const arr1 = Immutable([1, 2, 3]);

86

const arr2 = Immutable.from([1, 2, 3]);

87

```

88

89

### isImmutable

90

91

Checks whether a value is immutable according to seamless-immutable.

92

93

```javascript { .api }

94

/**

95

* Checks if a value is immutable

96

* @param {*} target - Value to check for immutability

97

* @returns {boolean} True if the value is immutable

98

*/

99

function isImmutable(target);

100

```

101

102

**Usage Examples:**

103

104

```javascript

105

const Immutable = require("seamless-immutable");

106

107

const mutableArray = [1, 2, 3];

108

const immutableArray = Immutable([1, 2, 3]);

109

110

console.log(Immutable.isImmutable(mutableArray)); // false

111

console.log(Immutable.isImmutable(immutableArray)); // true

112

113

// Primitives are considered immutable

114

console.log(Immutable.isImmutable("string")); // true

115

console.log(Immutable.isImmutable(42)); // true

116

console.log(Immutable.isImmutable(null)); // true

117

```

118

119

### ImmutableError

120

121

Error class thrown when attempting to use mutating methods on immutable data structures.

122

123

```javascript { .api }

124

/**

125

* Error thrown when attempting to use mutating methods on immutable structures

126

* @extends Error

127

*/

128

class ImmutableError extends Error {

129

constructor(message: string);

130

}

131

```

132

133

**Usage Example:**

134

135

```javascript

136

const Immutable = require("seamless-immutable");

137

138

const immutableArray = Immutable([1, 2, 3]);

139

140

try {

141

immutableArray.push(4); // This will throw

142

} catch (error) {

143

console.log(error instanceof Immutable.ImmutableError); // true

144

console.log(error.message); // "The push method cannot be invoked on an Immutable data structure."

145

}

146

```

147

148

### Static API

149

150

Alternative API that uses static methods instead of instance methods to avoid method name collisions.

151

152

```javascript { .api }

153

/**

154

* Static API version that avoids adding methods to object instances

155

* All instance methods are available as static methods instead

156

* When using static API, no instance methods are added to immutable objects

157

*/

158

const static;

159

```

160

161

**Usage Examples:**

162

163

```javascript

164

const Immutable = require("seamless-immutable").static;

165

166

const obj = {name: "Alice", age: 30};

167

const immutableObj = Immutable(obj);

168

169

// Instead of: immutableObj.merge({age: 31})

170

const updated = Immutable.merge(immutableObj, {age: 31});

171

172

// Instead of: immutableObj.set("status", "active")

173

const withStatus = Immutable.set(immutableObj, "status", "active");

174

175

// All static methods available:

176

// Immutable.merge, Immutable.set, Immutable.setIn, Immutable.without,

177

// Immutable.update, Immutable.updateIn, Immutable.getIn, Immutable.asMutable,

178

// Immutable.flatMap, Immutable.asObject

179

180

// Note: When using static API, instance methods are NOT available

181

console.log(typeof immutableObj.merge); // "undefined" - no instance methods added

182

```

183

184

**When to Use Static vs Instance API:**

185

186

- **Static API**: Recommended to avoid method name pollution, better for functional programming style, no risk of conflicts with existing object methods

187

- **Instance API**: More concise syntax, familiar object-oriented pattern, default behavior

188

- **Performance**: Both APIs have identical performance characteristics

189

190

### asMutable

191

192

Converts an immutable data structure back to a mutable one.

193

194

```javascript { .api }

195

/**

196

* Convert immutable structure to mutable copy

197

* @param {*} obj - Immutable structure to convert

198

* @param {Object} [options] - Conversion options

199

* @param {boolean} [options.deep] - Recursively convert nested immutable structures

200

* @returns {*} Mutable copy of the structure

201

*/

202

function asMutable(obj, options);

203

204

/**

205

* Convert immutable Date to mutable copy (Date-specific)

206

* @param {Date} date - Immutable Date to convert

207

* @returns {Date} New mutable Date with same time value

208

*/

209

function asMutable(date);

210

```

211

212

**Usage Examples:**

213

214

```javascript

215

const Immutable = require("seamless-immutable");

216

217

const immutableObj = Immutable({

218

name: "Alice",

219

hobbies: ["reading", "coding"],

220

address: {city: "NYC", state: "NY"}

221

});

222

223

// Shallow conversion - nested structures remain immutable

224

const shallowMutable = Immutable.asMutable(immutableObj);

225

shallowMutable.name = "Bob"; // Works

226

// shallowMutable.hobbies.push("gaming"); // Would still throw error

227

228

// Deep conversion - all nested structures become mutable

229

const deepMutable = Immutable.asMutable(immutableObj, {deep: true});

230

deepMutable.name = "Charlie"; // Works

231

deepMutable.hobbies.push("gaming"); // Also works now

232

deepMutable.address.city = "LA"; // Also works now

233

234

console.log(Immutable.isImmutable(shallowMutable)); // false

235

console.log(Immutable.isImmutable(deepMutable)); // false

236

237

// Date-specific asMutable

238

const immutableDate = Immutable(new Date("2023-01-01"));

239

const mutableDate = immutableDate.asMutable();

240

241

// Date methods that would throw on immutable dates now work

242

mutableDate.setFullYear(2024);

243

console.log(mutableDate.getFullYear()); // 2024

244

console.log(immutableDate.getFullYear()); // 2023 - original unchanged

245

```

246

247

## Special Behaviors

248

249

### React Elements

250

React elements are treated as immutable and passed through unchanged to avoid interfering with React's internal structure.

251

252

```javascript

253

const React = require("react");

254

const element = React.createElement("div", {className: "test"});

255

const result = Immutable(element);

256

console.log(element === result); // true - unchanged

257

console.log(Immutable.isImmutable(element)); // true - considered immutable

258

```

259

260

### Promises

261

Promises themselves are not made immutable, but their fulfillment values are automatically made immutable using a transformed promise.

262

263

```javascript

264

const promise = Promise.resolve([1, 2, 3]);

265

const wrappedPromise = Immutable(promise);

266

267

// The wrapped promise will resolve to an immutable array

268

wrappedPromise.then(result => {

269

console.log(Immutable.isImmutable(result)); // true - array is now immutable

270

console.log(Array.isArray(result)); // true - still an array

271

});

272

273

console.log(Immutable.isImmutable(wrappedPromise)); // false - promise itself not immutable

274

```

275

276

### Functions, Errors, Files, Blobs

277

These types are treated as immutable and returned unchanged. This is an intentional abstraction leak for practical reasons.

278

279

```javascript

280

const fn = function() { return "hello"; };

281

const error = new Error("test");

282

const file = new File(["content"], "test.txt");

283

const blob = new Blob(["content"]);

284

285

console.log(Immutable(fn) === fn); // true - unchanged

286

console.log(Immutable(error) === error); // true - unchanged

287

console.log(Immutable(file) === file); // true - unchanged

288

console.log(Immutable(blob) === blob); // true - unchanged

289

290

// All are considered immutable

291

console.log(Immutable.isImmutable(fn)); // true

292

console.log(Immutable.isImmutable(error)); // true

293

console.log(Immutable.isImmutable(file)); // true

294

console.log(Immutable.isImmutable(blob)); // true

295

```

296

297

### Null and Undefined

298

Primitives including `null` and `undefined` are naturally immutable and returned unchanged.

299

300

```javascript

301

console.log(Immutable(null) === null); // true

302

console.log(Immutable(undefined) === undefined); // true

303

console.log(Immutable.isImmutable(null)); // true

304

console.log(Immutable.isImmutable(undefined)); // true

305

```

306

307

### Development vs Production Builds

308

309

The library behaves differently depending on the build environment:

310

311

**Development Build (`process.env.NODE_ENV !== "production"`):**

312

- Objects and arrays are frozen using `Object.freeze()`

313

- Mutating methods throw helpful `ImmutableError` exceptions

314

- Circular reference protection with configurable stack depth (default 64 levels)

315

- Date mutating methods are banned and throw errors

316

317

**Production Build:**

318

- No freezing for better performance (~2x speed improvement)

319

- No defensive method banning (methods still won't work, but fail silently)

320

- No circular reference checking

321

- Smaller bundle size

322

323

```javascript

324

// Development build behavior

325

const arr = Immutable([1, 2, 3]);

326

try {

327

arr.push(4); // Throws ImmutableError with helpful message

328

} catch (e) {

329

console.log(e.message); // "The push method cannot be invoked on an Immutable data structure."

330

}

331

332

// Production build behavior

333

const arr = Immutable([1, 2, 3]);

334

arr.push(4); // Fails silently, arr remains [1, 2, 3]

335

```

336

337

### Circular Reference Protection

338

339

In development builds, the constructor includes protection against circular references with a configurable stack depth limit (default 64 levels).

340

341

```javascript

342

// This would throw an ImmutableError after 64 levels of nesting (development only)

343

const deepObject = {};

344

let current = deepObject;

345

for (let i = 0; i < 100; i++) {

346

current.nested = {};

347

current = current.nested;

348

}

349

// Immutable(deepObject); // Throws error about deeply nested object

350

351

// Increase limit for legitimately deep objects

352

const deeperAllowed = Immutable(deepObject, null, 256);

353

```