typescript - Readonly Store som utökar BehaviorSubject


Jag har ett problem med nestlade objekt som är lagrade i BehaviorSubjects som tillåter mutationer inne i en applikation som jag arbetar med (RxJs & TypeScript med Angular).

Jag vill lösa detta genom att skapa en ny typ Store som utökar BehaviorSubject men ser till att all data som lagras är oföränderlig.

Jag har hamnat med mer eller mindre denna klass:

export class Store<T> extends BehaviorSubject<T> {
  constructor(initialData: T) {
    super(deepFreeze(initialData));
  }

  next(newData: T): void {
    super.next(deepFreeze(newData));
  }

  getValue(): Readonly<T> {
    return super.getValue() as Readonly<T>;
  }
}

Vilket ger mig ett körtidsfel när jag försöker ändra objekt på det här sättet:

someStore$ = new Store({ firstLevel: { secondLevel: [] }});

someStore$.subscribe(val => val.firstLevel.secondLevel = ["que?"]);

Men jag skulle också vilja att TypeScript låter utvecklare veta att operationen är ogiltig, så att linter kan instruera utvecklaren att han/hon gör något olagligt.

Hur går jag tillväga för att göra detta korrekt? Måste jag på något sätt åsidosätta subscribe-funktionen inuti Store? Jag hoppades att det skulle räcka att kasta Readonly runt returtypen av getValue(), men varken exemplet ovan eller följande exempel ger mig ett lint-fel:

someStore$.getValue().firstLevel.secondLevel = ["si!"]

Hur skulle jag gå tillväga för att säkerställa att oföränderlighet av dessa objekt meddelas med Typescript och inte bara fel under körning?

Som referens implementeras deepFreeze som följande:

export function deepFreeze<T>(object: T): Readonly<T> {
  const propNames = Object.getOwnPropertyNames(object);
  for (const name of propNames) {
    const value = object[name];
    object[name] =
      value && typeof value === "object" ? deepFreeze(value) : value;
  }

  return Object.freeze(object);
}

(Baserat på MDN-dokumentationen av Object.freeze)