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.
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.
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.
// Use RecordFactory<TProps> for defining new Record factory functions. typePoint3DProps = { x: number, y: number, z: number }; constdefaultValues: Point3DProps = { x:0, y:0, z:0 }; constmakePoint3D: RecordFactory<Point3DProps> = Record(defaultValues); exportmakePoint3D;
// Use RecordOf<T> for defining new instances of that Record. exporttypePoint3D = RecordOf<Point3DProps>; constsome3DPoint: 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:
setName(name: string): this { returnthis.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.
A record is similar to a JS object, but enforces a specific set of allowed string keys, and has default values.
The
Record()function produces new Record Factories, which when called create Record instances.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.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.
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.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
classform, 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 ofnewwhen creating new Record instances if they are defined as aclass.Flow Typing Records:
Immutable.js exports two Flow types designed to make it easier to use Records with flow typed code,
RecordOf<TProps>andRecordFactory<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), useRecordOf<TProps>.Typically, new Record definitions will export both the Record factory function as well as the Record instance type for use in other code.
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: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()andsetIn()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()orrecord.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 aMapor values in aSet, 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.