addons/shared/immutableExt.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {ValueObject} from 'immutable';
b69ab319
b69ab3110const IS_RECORD_SYMBOL = '@@__IMMUTABLE_RECORD__@@';
b69ab3111
b69ab3112/** Wraps a ValueObject so it self-updates on equals. */
b69ab3113export class SelfUpdate<T extends ValueObject> implements ValueObject {
b69ab3114 inner: T;
b69ab3115
b69ab3116 /**
b69ab3117 * Tell Recoil to not deepFreeze (Object.seal) this object. This is needed
b69ab3118 * since we might update the `inner` field. We didn't break Recoil
b69ab3119 * assumptions since we maintain the same "value" of the object.
b69ab3120 *
b69ab3121 * See https://github.com/facebookexperimental/Recoil/blob/0.7.7/packages/shared/util/Recoil_deepFreezeValue.js#L42
b69ab3122 * Recoil tests `value[IS_RECORD_SYMBOL] != null`.
b69ab3123 *
b69ab3124 * For immutable.js, it actually checks the boolean value.
b69ab3125 * See https://github.com/immutable-js/immutable-js/blob/v4.3.4/src/predicates/isRecord.js
b69ab3126 * Immutable.js uses `Boolean(maybeRecord && maybeRecord[IS_RECORD_SYMBOL])`.
b69ab3127 *
b69ab3128 * By using `false`, this tricks Recoil to treat us as an immutable value,
b69ab3129 * while does not break Immutable.js' type checking.
b69ab3130 */
b69ab3131 [IS_RECORD_SYMBOL] = false;
b69ab3132
b69ab3133 constructor(inner: T) {
b69ab3134 this.inner = inner;
b69ab3135 }
b69ab3136
b69ab3137 hashCode(): number {
b69ab3138 return this.inner.hashCode() + 1;
b69ab3139 }
b69ab3140
b69ab3141 equals(other: unknown): boolean {
b69ab3142 if (!(other instanceof SelfUpdate)) {
b69ab3143 return false;
b69ab3144 }
b69ab3145 if (this === other) {
b69ab3146 return true;
b69ab3147 }
b69ab3148 const otherInner = other.inner;
b69ab3149 const result = this.inner.equals(otherInner);
b69ab3150 if (result && this.inner !== otherInner) {
b69ab3151 this.inner = otherInner;
b69ab3152 }
b69ab3153 return result;
b69ab3154 }
b69ab3155}