| 227 | } |
| 228 | |
| 229 | class PropRefImpl<A, K extends keyof A> implements AtomRef<A[K]> { |
| 230 | readonly [TypeId]: TypeId |
| 231 | readonly key = keyState.generate() |
| 232 | private previous: A[K] |
| 233 | readonly parent: AtomRef<A> |
| 234 | readonly _prop: K |
| 235 | |
| 236 | constructor(parent: AtomRef<A>, _prop: K) { |
| 237 | this[TypeId] = TypeId |
| 238 | this.parent = parent |
| 239 | this._prop = _prop |
| 240 | this.previous = parent.value[_prop] |
| 241 | } |
| 242 | [Equal.symbol](that: Equal.Equal) { |
| 243 | return Equal.equals(this.value, (that as ReadonlyRef<A>).value) |
| 244 | } |
| 245 | [Hash.symbol]() { |
| 246 | return Hash.hash(this.value) |
| 247 | } |
| 248 | get value() { |
| 249 | if (this.parent.value && this._prop in (this.parent.value as any)) { |
| 250 | this.previous = this.parent.value[this._prop] |
| 251 | } |
| 252 | return this.previous |
| 253 | } |
| 254 | subscribe(f: (a: A[K]) => void): () => void { |
| 255 | let previous = this.value |
| 256 | return this.parent.subscribe((a) => { |
| 257 | if (!a || !(this._prop in (a as any))) { |
| 258 | return |
| 259 | } |
| 260 | const next = a[this._prop] |
| 261 | if (Equal.equals(next, previous)) { |
| 262 | return |
| 263 | } |
| 264 | previous = next |
| 265 | f(next) |
| 266 | }) |
| 267 | } |
| 268 | map<C>(f: (a: A[K]) => C): ReadonlyRef<C> { |
| 269 | return new MapRefImpl(this, f) |
| 270 | } |
| 271 | prop<CK extends keyof A[K]>(prop: CK): AtomRef<A[K][CK]> { |
| 272 | return new PropRefImpl(this, prop) |
| 273 | } |
| 274 | set(value: A[K]): AtomRef<A[K]> { |
| 275 | if (Array.isArray(this.parent.value)) { |
| 276 | const newArray = this.parent.value.slice() |
| 277 | newArray[this._prop as number] = value |
| 278 | this.parent.set(newArray as A) |
| 279 | } else { |
| 280 | this.parent.set({ |
| 281 | ...this.parent.value, |
| 282 | [this._prop]: value |
| 283 | }) |
| 284 | } |
| 285 | return this |
| 286 | } |
nothing calls this directly
no test coverage detected
searching dependent graphs…