immutable-record v1.0.5
immutable-record -- typed & immutable Javascript objects
immutable-record is a small JavaScript library inspired by Facebook's ImmutableJS
that allows you to create immutable Records.
Records behave very much like Objects (even Object.keys()), but they are
typed and immutable.
What does it look like?
// ImmutableRecord() returns a Record class
import ImmutableRecord from 'immutable-record'
const Record = ImmutableRecord({
foo: { default: 5 },
optional: { type: 'number' }
someField: {
type: value => 'foo' in value,
required: true
},
})
// You just pass ordinary objects to the Record constructor
const object = new Record({
someField: { foo: 'bar' }
// You don't have to provide optional fields
})
// Object.keys() works as if the Record was a normal Object
Object.keys(object) // [ 'foo', 'someField' ]
// Records are immutable, so Record#set() returns a new Record
const another = object.set('optional', 8)
another.optional // 8
// Validation happens automatically
object.remove('someField')
// Error: "someField" is missing from the record {"foo":5}Why pick immutable-record ?
Compared to ImmutableJS, the key feature is automatic validation. With
immutable-record, you can specify a type of each field and it will be
automatically checked. Additionally:
Object.keys()works just how you would expect- You can mark fields as
required - You can create optional fields that may not be present on a record, but will validate when set.
Documentation
Installing
# immutable-record is available on npm
npm install --save immutable-recordImporting
import ImmutableRecord from 'immutable-record'
// If you're not using ES6 modules
const ImmutableRecord = require('immutable-record')Creating Records
The ImmutableRecord() function takes an object whose values describe the validation that is applied to the fields.
const Record = ImmutableRecord({
optional: { type: 'string' },
required: { required: true },
validation: {
type: value => value > 5,
default: 6
})You can also pass a second parameter to the ImmutableRecord() function which specifies a custom name for the Record class.
const Foo = ImmutableRecord({
foo: { type: 'string' }
}, 'Foo')
Foo.name === 'Foo' // true
console.log(Foo) // [Function: Foo]There are three validation options available for each field:
type,required, anddefault
The type option
A primitive string (AKA one of the values returned by typeof). The possible values at the time of writing are:
'object', 'string', 'number', 'symbol', 'boolean', function', 'undefined'
A validation function that takes a single argument (the field's value) and returns a boolean.
const Record = ImmutableRecord({
// Strings (typeof x === 'string') are valid
string: { type: 'string' },
// Arrays of length 4 or greater are valid
array: {
type: value => (
Array.isArray(value) &&
value.length > 3
)
}
})The default option
If a field has a default and a Record is created without the field explicitly set, the default value is used automatically.
const Record = ImmutableRecord({
withDefault: { default: 5 }
})
// The default is automatically used if the field isn't set
const object = new Record({})
object.withDefault // 5
// undefined is a legal field value, so the default won't be used
const noDefault = new Record({
withDefault: undefined
})
noDefault.withDefault // undefinedThe required option
Fields marked as "required" must be present on the Record for it to validate.
const Record = ImmutableRecord({
required: { required: true },
optional: { required: false }
})
// No problems here
const object = new Record({
required: 1
})
'optional' in object // false
// This doesn't work
const bad = new Record({
optional: 1
})
// Error: "required" is missing from the record {"optional":1}If a field is required and it also has a default, the Record will still validate even if the field isn't set.
const Record = ImmutableRecord({
field: {
required: true,
default: 5
}
})
// No problems here
const object = new Record({})
object.field // 5Fields with no options
You can also leave the options out to get optional, untyped fields.
const Record = ImmutableRecord({
optionalUntyped: {},
// setting the field equal to null works too
alsoWorks: null
})Using Records
Records mostly work just like normal Objects, except they're immutable.
const ABCRecord = ImmutableRecord({
a: {}, b: {}, c: {}
})
const object = new ABCRecord({ a: 1, c: 3 })
object.a // 1
object.c // 3
object.b // undefined
'b' in object // false
// Object.keys() also works how you would expect
Object.keys(object) // [ 'a', 'c' ]When you try to set or delete a Record's value directly, the Record will throw.
const object = new ABCRecord({ a: 1, c: 3 })
object.b = 2
// Error: Use the "set" function to update the values of an ImmutableRecord.
delete object.a
// TypeError: Cannot delete property 'a' of [object Object]Record#set()
Use the set() function to update Record values. set() returns a new Record instance.
const object = new ABCRecord({ a: 1, c: 3 })
const withB = object.set('b', 2)
withB instanceof ABCRecord // true
withB.b // 2
// The original record is unmodified
object.b // undefinedRecord#remove()
Use the remove() function to remove Record values. remove() returns a new Record instance.
const object = new ABCRecord({ a: 1, b: 2, c: 3 })
const withoutB = object.remove('b')
withoutB instanceof ABCRecord // true
withoutB.b // undefinedA point about validation
Records are validated when they are constructed, so all of your fields will be validated
when you use set() and remove().