Record

A record is similar to a JS object, but enforces a specific set of allowed string keys, and has default values.

type Record<TProps>

Discussion

The Record() function produces new Record Factories, which when called create Record instances.

const { Record } = require('immutable')
const ABRecord = Record({ a: 1, b: 2 })
const myRecord = ABRecord({ b: 3 })

Records always have a value for the keys they define. removeing a key from a record simply resets it to the default value for that key.

myRecord.get('a') // 1
myRecord.get('b') // 3
const myRecordWithoutB = myRecord.remove('b')
myRecordWithoutB.get('b') // 2

Values provided to the constructor not found in the Record type will be ignored. For example, in this case, ABRecord is provided a key "x" even though only "a" and "b" have been defined. The value for "x" will be ignored for this record.

const myRecord = ABRecord({ b: 3, x: 10 })
myRecord.get('x') // undefined

Because Records have a known set of string keys, property get access works as expected, however property sets will throw an Error.

Note: IE8 does not support property access. Only use get() when supporting IE8.

myRecord.b // 3
myRecord.b = 5 // throws Error

Record Types can be extended as well, allowing for custom methods on your Record. This is not a common pattern in functional environments, but is in many JS programs.

However Record Types are more restricted than typical JavaScript classes. They do not use a class constructor, which also means they cannot use class properties (since those are technically part of a constructor).

While Record Types can be syntactically created with the JavaScript class form, the resulting Record function is actually a factory function, not a class constructor. Even though Record Types are not classes, JavaScript currently requires the use of new when creating new Record instances if they are defined as a class.

class ABRecord extends Record({ a: 1, b: 2 }) {
  getAB() {
    return this.a + this.b;
  }
}

var myRecord = new ABRecord({b: 3})
myRecord.getAB() // 4

Flow Typing Records:

Immutable.js exports two Flow types designed to make it easier to use Records with flow typed code, RecordOf<TProps> and RecordFactory<TProps>.

When defining a new kind of Record factory function, use a flow type that describes the values the record contains along with RecordFactory<TProps>. To type instances of the Record (which the factory function returns), use RecordOf<TProps>.

Typically, new Record definitions will export both the Record factory function as well as the Record instance type for use in other code.

import type { RecordFactory, RecordOf } from 'immutable';

// Use RecordFactory<TProps> for defining new Record factory functions.
type Point3DProps = { x: number, y: number, z: number };
const defaultValues: Point3DProps = { x: 0, y: 0, z: 0 };
const makePoint3D: RecordFactory<Point3DProps> = Record(defaultValues);
export makePoint3D;

// Use RecordOf<T> for defining new instances of that Record.
export type Point3D = RecordOf<Point3DProps>;
const some3DPoint: Point3D = makePoint3D({ x: 10, y: 20, z: 30 });

Flow Typing Record Subclasses:

Records can be subclassed as a means to add additional methods to Record instances. This is generally discouraged in favor of a more functional API, since Subclasses have some minor overhead. However the ability to create a rich API on Record types can be quite valuable.

When using Flow to type Subclasses, do not use RecordFactory<TProps>, instead apply the props type when subclassing:

type PersonProps = {name: string, age: number};
const defaultValues: PersonProps = {name: 'Aristotle', age: 2400};
const PersonRecord = Record(defaultValues);
class Person extends PersonRecord<PersonProps> {
  getName(): string {
    return this.get('name')
  }

  setName(name: string): this {
    return this.set('name', name);
  }
}

Choosing Records vs plain JavaScript objects

Records offer a persistently immutable alternative to plain JavaScript objects, however they're not required to be used within Immutable.js collections. In fact, the deep-access and deep-updating functions like getIn() and setIn() work with plain JavaScript Objects as well.

Deciding to use Records or Objects in your application should be informed by the tradeoffs and relative benefits of each:

  • Runtime immutability: plain JS objects may be carefully treated as immutable, however Record instances will throw if attempted to be mutated directly. Records provide this additional guarantee, however at some marginal runtime cost. While JS objects are mutable by nature, the use of type-checking tools like Flow can help gain confidence in code written to favor immutability.

  • Value equality: Records use value equality when compared with is() or record.equals(). That is, two Records with the same keys and values are equal. Plain objects use reference equality. Two objects with the same keys and values are not equal since they are different objects. This is important to consider when using objects as keys in a Map or values in a Set, which use equality when retrieving values.

  • API methods: Records have a full featured API, with methods like .getIn(), and .equals(). These can make working with these values easier, but comes at the cost of not allowing keys with those names.

  • Default values: Records provide default values for every key, which can be useful when constructing Records with often unchanging values. However default values can make using Flow and TypeScript more laborious.

  • Serialization: Records use a custom internal representation to efficiently store and update their values. Converting to and from this form isn't free. If converting Records to plain objects is common, consider sticking with plain objects to begin with.

Construction

Record()

Unlike other types in Immutable.js, the Record() function creates a new Record Factory, which is a function that creates Record instances.

Record<TProps>(defaultValues: TProps, name?: string): Record.Factory<TProps>

Discussion

See above for examples of using Record().

Note: Record is a factory function and not a class, and does not use the new keyword during construction.

Static methods

Record.isRecord()

Record.isRecord(maybeRecord: unknown): boolean

Record.getDescriptiveName()

Record.getDescriptiveName(record: Record<any>): string

Reading values

has()

has(key: string): boolean

get()

get<K>(key: K, notSetValue?: unknown): TProps,[K]
get<T>(key: string, notSetValue: T): T

Reading deep values

hasIn()

hasIn(keyPath: Iterable<unknown>): boolean

getIn()

getIn(keyPath: Iterable<unknown>): unknown

Value equality

equals()

equals(other: unknown): boolean

hashCode()

hashCode(): number

Persistent changes

set()

set<K>(key: K, value: TProps,[K]): this

update()

update<K>(key: K, updater: (value: TProps,[K]) => TProps,[K]): this

merge()

merge(...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this

mergeDeep()

mergeDeep(...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this

mergeWith()

mergeWith(merger: (oldVal: unknown, newVal: unknown, key: keyof TProps) => unknown,...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this

mergeDeepWith()

mergeDeepWith(merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown,...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this

delete()

Returns a new instance of this Record type with the value for the specific key set to its default value.

delete<K>(key: K): this

alias

remove()

clear()

Returns a new instance of this Record type with all values set to their default values.

clear(): this

Deep persistent changes

setIn()

setIn(keyPath: Iterable<unknown>, value: unknown): this

updateIn()

updateIn(keyPath: Iterable<unknown>, updater: (value: unknown) => unknown): this

mergeIn()

mergeIn(keyPath: Iterable<unknown>, ...collections: Array<unknown>): this

mergeDeepIn()

mergeDeepIn(keyPath: Iterable<unknown>, ...collections: Array<unknown>): this

deleteIn()

deleteIn(keyPath: Iterable<unknown>): this

alias

removeIn()

Conversion to JavaScript types

toJS()

Deeply converts this Record to equivalent native JavaScript Object.

toJS(): {[key: string]: unknown}

Discussion

Note: This method may not be overridden. Objects with custom serialization to plain JS may override toJSON() instead.

toJSON()

Shallowly converts this Record to equivalent native JavaScript Object.

toJSON(): TProps

toObject()

Shallowly converts this Record to equivalent JavaScript Object.

toObject(): TProps

Transient changes

withMutations()

Note: Not all methods can be used on a mutable collection or within withMutations! Only set may be used mutatively.

withMutations(mutator: (mutable: this) => unknown): this

see

asMutable()

asMutable(): this

see

wasAltered()

wasAltered(): boolean

see

asImmutable()

asImmutable(): this

see

Sequence algorithms

toSeq()

toSeq(): Seq.Keyed<keyof TProps, TProps,[keyof TProps]>

[Symbol.iterator]()

[Symbol.iterator](): IterableIterator<[keyof TProps, TProps,[keyof TProps]]>
This documentation is generated from immutable.d.ts. Pull requests and Issues welcome.

© 2014–present, Lee Byron and other contributors
Licensed under the 3-clause BSD License.
https://immutable-js.com/docs/v4.0.0/Record/