@@ -47,11 +47,11 @@ export interface LiveMapData extends LiveObjectData {
4747 data : Map < string , LiveMapEntry > ;
4848}
4949
50- export interface LiveMapUpdate extends LiveObjectUpdate {
51- update : { [ keyName : string ] : 'updated' | 'removed' } ;
50+ export interface LiveMapUpdate < T extends API . LiveMapType > extends LiveObjectUpdate {
51+ update : { [ keyName in keyof T & string ] ? : 'updated' | 'removed' } ;
5252}
5353
54- export class LiveMap < T extends API . LiveMapType > extends LiveObject < LiveMapData , LiveMapUpdate > {
54+ export class LiveMap < T extends API . LiveMapType > extends LiveObject < LiveMapData , LiveMapUpdate < T > > {
5555 constructor (
5656 objects : Objects ,
5757 private _semantics : MapSemantics ,
@@ -391,7 +391,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
391391 return ;
392392 }
393393
394- let update : LiveMapUpdate | LiveObjectUpdateNoop ;
394+ let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
395395 switch ( op . action ) {
396396 case ObjectOperationAction . MAP_CREATE :
397397 update = this . _applyMapCreate ( op ) ;
@@ -435,7 +435,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
435435 /**
436436 * @internal
437437 */
438- overrideWithObjectState ( objectState : ObjectState ) : LiveMapUpdate | LiveObjectUpdateNoop {
438+ overrideWithObjectState ( objectState : ObjectState ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
439439 if ( objectState . objectId !== this . getObjectId ( ) ) {
440440 throw new this . _client . ErrorInfo (
441441 `Invalid object state: object state objectId=${ objectState . objectId } ; LiveMap objectId=${ this . getObjectId ( ) } ` ,
@@ -526,21 +526,23 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
526526 return { data : new Map < string , LiveMapEntry > ( ) } ;
527527 }
528528
529- protected _updateFromDataDiff ( prevDataRef : LiveMapData , newDataRef : LiveMapData ) : LiveMapUpdate {
530- const update : LiveMapUpdate = { update : { } } ;
529+ protected _updateFromDataDiff ( prevDataRef : LiveMapData , newDataRef : LiveMapData ) : LiveMapUpdate < T > {
530+ const update : LiveMapUpdate < T > = { update : { } } ;
531531
532532 for ( const [ key , currentEntry ] of prevDataRef . data . entries ( ) ) {
533+ const typedKey : keyof T & string = key ;
533534 // any non-tombstoned properties that exist on a current map, but not in the new data - got removed
534- if ( currentEntry . tombstone === false && ! newDataRef . data . has ( key ) ) {
535- update . update [ key ] = 'removed' ;
535+ if ( currentEntry . tombstone === false && ! newDataRef . data . has ( typedKey ) ) {
536+ update . update [ typedKey ] = 'removed' ;
536537 }
537538 }
538539
539540 for ( const [ key , newEntry ] of newDataRef . data . entries ( ) ) {
540- if ( ! prevDataRef . data . has ( key ) ) {
541+ const typedKey : keyof T & string = key ;
542+ if ( ! prevDataRef . data . has ( typedKey ) ) {
541543 // if property does not exist in the current map, but new data has it as a non-tombstoned property - got updated
542544 if ( newEntry . tombstone === false ) {
543- update . update [ key ] = 'updated' ;
545+ update . update [ typedKey ] = 'updated' ;
544546 continue ;
545547 }
546548
@@ -551,17 +553,17 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
551553 }
552554
553555 // properties that exist both in current and new map data need to have their values compared to decide on the update type
554- const currentEntry = prevDataRef . data . get ( key ) ! ;
556+ const currentEntry = prevDataRef . data . get ( typedKey ) ! ;
555557
556558 // compare tombstones first
557559 if ( currentEntry . tombstone === true && newEntry . tombstone === false ) {
558560 // current prop is tombstoned, but new is not. it means prop was updated to a meaningful value
559- update . update [ key ] = 'updated' ;
561+ update . update [ typedKey ] = 'updated' ;
560562 continue ;
561563 }
562564 if ( currentEntry . tombstone === false && newEntry . tombstone === true ) {
563565 // current prop is not tombstoned, but new is. it means prop was removed
564- update . update [ key ] = 'removed' ;
566+ update . update [ typedKey ] = 'removed' ;
565567 continue ;
566568 }
567569 if ( currentEntry . tombstone === true && newEntry . tombstone === true ) {
@@ -572,28 +574,28 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
572574 // both props exist and are not tombstoned, need to compare values with deep equals to see if it was changed
573575 const valueChanged = ! deepEqual ( currentEntry . data , newEntry . data , { strict : true } ) ;
574576 if ( valueChanged ) {
575- update . update [ key ] = 'updated' ;
577+ update . update [ typedKey ] = 'updated' ;
576578 continue ;
577579 }
578580 }
579581
580582 return update ;
581583 }
582584
583- protected _mergeInitialDataFromCreateOperation ( objectOperation : ObjectOperation ) : LiveMapUpdate {
585+ protected _mergeInitialDataFromCreateOperation ( objectOperation : ObjectOperation ) : LiveMapUpdate < T > {
584586 if ( this . _client . Utils . isNil ( objectOperation . map ) ) {
585587 // if a map object is missing for the MAP_CREATE op, the initial value is implicitly an empty map.
586588 // in this case there is nothing to merge into the current map, so we can just end processing the op.
587589 return { update : { } } ;
588590 }
589591
590- const aggregatedUpdate : LiveMapUpdate | LiveObjectUpdateNoop = { update : { } } ;
592+ const aggregatedUpdate : LiveMapUpdate < T > = { update : { } } ;
591593 // in order to apply MAP_CREATE op for an existing map, we should merge their underlying entries keys.
592594 // we can do this by iterating over entries from MAP_CREATE op and apply changes on per-key basis as if we had MAP_SET, MAP_REMOVE operations.
593595 Object . entries ( objectOperation . map . entries ?? { } ) . forEach ( ( [ key , entry ] ) => {
594596 // for a MAP_CREATE operation we must use the serial value available on an entry, instead of a serial on a message
595597 const opSerial = entry . timeserial ;
596- let update : LiveMapUpdate | LiveObjectUpdateNoop ;
598+ let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
597599 if ( entry . tombstone === true ) {
598600 // entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op
599601 update = this . _applyMapRemove ( { key } , opSerial ) ;
@@ -624,7 +626,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
624626 ) ;
625627 }
626628
627- private _applyMapCreate ( op : ObjectOperation ) : LiveMapUpdate | LiveObjectUpdateNoop {
629+ private _applyMapCreate ( op : ObjectOperation ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
628630 if ( this . _createOperationIsMerged ) {
629631 // There can't be two different create operation for the same object id, because the object id
630632 // fully encodes that operation. This means we can safely ignore any new incoming create operations
@@ -649,7 +651,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
649651 return this . _mergeInitialDataFromCreateOperation ( op ) ;
650652 }
651653
652- private _applyMapSet ( op : MapOp , opSerial : string | undefined ) : LiveMapUpdate | LiveObjectUpdateNoop {
654+ private _applyMapSet ( op : MapOp , opSerial : string | undefined ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
653655 const { ErrorInfo, Utils } = this . _client ;
654656
655657 const existingEntry = this . _dataRef . data . get ( op . key ) ;
@@ -698,10 +700,15 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
698700 } ;
699701 this . _dataRef . data . set ( op . key , newEntry ) ;
700702 }
701- return { update : { [ op . key ] : 'updated' } } ;
703+
704+ const update : LiveMapUpdate < T > = { update : { } } ;
705+ const typedKey : keyof T & string = op . key ;
706+ update . update [ typedKey ] = 'updated' ;
707+
708+ return update ;
702709 }
703710
704- private _applyMapRemove ( op : MapOp , opSerial : string | undefined ) : LiveMapUpdate | LiveObjectUpdateNoop {
711+ private _applyMapRemove ( op : MapOp , opSerial : string | undefined ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
705712 const existingEntry = this . _dataRef . data . get ( op . key ) ;
706713 if ( existingEntry && ! this . _canApplyMapOperation ( existingEntry . timeserial , opSerial ) ) {
707714 // the operation's serial <= the entry's serial, ignore the operation.
@@ -729,7 +736,11 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
729736 this . _dataRef . data . set ( op . key , newEntry ) ;
730737 }
731738
732- return { update : { [ op . key ] : 'removed' } } ;
739+ const update : LiveMapUpdate < T > = { update : { } } ;
740+ const typedKey : keyof T & string = op . key ;
741+ update . update [ typedKey ] = 'removed' ;
742+
743+ return update ;
733744 }
734745
735746 /**
0 commit comments