Запись
Запись похожа на JS-объект, но навязывает определённый набор разрешённых строковых ключей и имеет значения по умолчанию.
type Record<TProps>
Обсуждение
Функция Record() создаёт новые фабрики записей, которые при вызове создают экземпляры записей.
const { Record } = require('immutable')
const ABRecord = Record({ a: 1, b: 2 })
const myRecord = ABRecord({ b: 3 })
Записи всегда имеют значение для определённых ключей. remove ключа из записи просто сбрасывает его до значения по умолчанию для этого ключа.
myRecord.get('a') // 1
myRecord.get('b') // 3
const myRecordWithoutB = myRecord.remove('b')
myRecordWithoutB.get('b') // 2
Значения, предоставленные конструктору, не найденные в типе записи, будут проигнорированы. Например, в данном случае ABRecord получает ключ "x", хотя определены только "a" и "b". Значение для "x" будет проигнорировано для этой записи.
const myRecord = ABRecord({ b: 3, x: 10 })
myRecord.get('x') // undefined
Поскольку у записей есть известный набор строковых ключей, доступ к свойствам через получение работает как ожидается, но попытка изменения свойства вызовет ошибку.
Примечание: IE8 не поддерживает доступ к свойствам. Используйте только get() при поддержке IE8.
myRecord.b // 3 myRecord.b = 5 // throws Error
Типы записей также могут быть расширены, что позволяет добавлять пользовательские методы к вашим записям. Это не распространённый шаблон в функциональных средах, но используется во многих JS-программах.
Однако типы записей более ограничены, чем типичные классы JavaScript. Они не используют конструктор класса, что также означает, что они не могут использовать свойства класса (поскольку они технически являются частью конструктора).
Хотя типы записей могут быть синтаксически созданы с помощью JavaScript class формы, полученная функция записи фактически является фабричной функцией, а не конструктором класса. Несмотря на то, что типы записей не являются классами, JavaScript в настоящее время требует использования new при создании новых экземпляров записей, если они определены как 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:
Immutable.js экспортирует два типа Flow, предназначенные для упрощения работы с записями в типизированном коде Flow, RecordOf<TProps> и RecordFactory<TProps>.
При определении новой фабричной функции записи используйте тип Flow, описывающий значения, содержащиеся в записи, вместе с RecordFactory<TProps>. Для типизации экземпляров записи (которые возвращает фабричная функция) используйте RecordOf<TProps>.
Обычно новые определения записей экспортируют как фабричную функцию записи, так и тип экземпляра записи для использования в других частях кода.
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:
Записи могут быть подклассифицированы как способ добавления дополнительных методов к экземплярам записей. Это обычно не рекомендуется в пользу более функционального API, так как подклассы имеют незначительные накладные расходы. Однако возможность создания богатого API на типах записей может быть весьма ценной.
При использовании Flow для типизации подклассов не используйте RecordFactory<TProps>, а вместо этого применяйте тип props при подклассификации:
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);
}
}
Выбор записей по сравнению с обычными JavaScript-объектами
Записи предлагают постоянно неизменяемую альтернативу обычным JavaScript-объектам, однако они не обязательны для использования в коллекциях Immutable.js. Фактически, функции глубокого доступа и глубокого обновления, такие как getIn() и setIn(), работают и с обычными JavaScript-объектами.
Решение использовать записи или объекты в вашем приложении должно основываться на взвешивании компромиссов и относительных преимуществ каждого варианта:
-
Неизменяемость во время выполнения: обычные JS-объекты могут быть аккуратно обработаны как неизменяемые, но попытка прямого изменения экземпляров записей вызовет ошибку. Записи обеспечивают это дополнительное гарантирование, однако с некоторыми незначительными затратами во время выполнения. Хотя JS-объекты по своей природе изменяемы, использование средств проверки типов, таких как Flow, может помочь в повышении уверенности в коде, написанном с упором на неизменяемость.
-
Равенство по значению: записи используют равенство по значению при сравнении с
is()илиrecord.equals(). То есть две записи с одинаковыми ключами и значениями равны. Обычные объекты используют равенство по ссылке. Два объекта с одинаковыми ключами и значениями не равны, так как они являются разными объектами. Это важно учитывать при использовании объектов в качестве ключей вMapили значениях вSet, которые используют равенство при получении значений. -
Методы API: записи имеют полный набор API с методами, такими как
.getIn(), и.equals(). Это может упростить работу с этими значениями, но вносит ограничения на использование ключей с такими именами. -
Значения по умолчанию: записи предоставляют значения по умолчанию для каждого ключа, что может быть полезно при создании записей с часто неизменными значениями. Однако значения по умолчанию могут затруднить использование Flow и TypeScript.
-
Сериализация: записи используют специальное внутреннее представление для эффективного хранения и обновления своих значений. Преобразование в и из этой формы не бесплатно. Если преобразование записей в обычные объекты часто используется, лучше начать с обычных объектов.
Создание
Record()
В отличие от других типов в Immutable.js, функция Record() создаёт новую фабрику записей, которая является функцией, создающей экземпляры записей.
Record<TProps>(defaultValues: TProps, name?: string): Record.Factory<TProps>
Обсуждение
Статические методы
Record.isRecord()
Record.isRecord(maybeRecord: unknown): boolean
Record.getDescriptiveName()
Record.getDescriptiveName(record: Record<any>): string
Чтение значений
has()
has(key: string): boolean
get()
get<K>(key: K, notSetValue?: unknown): TProps,[K] get<T>(key: string, notSetValue: T): T
Чтение глубоких значений
hasIn()
hasIn(keyPath: Iterable<unknown>): boolean
getIn()
getIn(keyPath: Iterable<unknown>): unknown
Равенство значений
equals()
equals(other: unknown): boolean
hashCode()
hashCode(): number
Постоянные изменения
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()
Возвращает новый экземпляр этого типа записи со значением для указанного ключа, установленным в его значение по умолчанию.
delete<K>(key: K): this
псевдоним
remove()
clear()
Возвращает новый экземпляр этого типа записи со всеми значениями, установленными в их значения по умолчанию.
clear(): this
Глубокие постоянные изменения
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
псевдоним
removeIn()
Преобразование в JavaScript-типы
toJS()
Глубоко преобразует эту запись в эквивалентный объект JavaScript.
toJS(): DeepCopy<TProps>
Обсуждение
Примечание: Этот метод не может быть переопределён. Объекты с пользовательской сериализацией в обычный JS могут переопределить toJSON() вместо этого.
toJSON()
Поверхностно преобразует эту запись в эквивалентный объект JavaScript.
toJSON(): TProps
toObject()
Поверхностно преобразует эту запись в эквивалентный объект JavaScript.
toObject(): TProps
Временные изменения
withMutations()
Примечание: не все методы могут быть использованы с изменяемой коллекцией или в withMutations! Только set может быть использован изменяемым образом.
withMutations(mutator: (mutable: this) => unknown): this
см
Алгоритмы последовательностей
toSeq()
toSeq(): Seq.Keyed<keyof TProps, TProps,[keyof TProps]>
[Symbol.iterator]()
[Symbol.iterator](): IterableIterator<[keyof TProps, TProps,[keyof TProps]]>
© 2014–present, Lee Byron and other contributors
Licensed under the 3-clause BSD License.
https://immutable-js.com/docs/v4.2.1/Record/