网站搜索

typescript - 扩展 BehaviorSubject 的只读存储


我在处理一个问题,该问题涉及存储在 BehaviorSubject 中的嵌套对象,这些对象允许在我正在开发的应用程序(RxJs 和 TypeScript 与 Angular)中进行变更。

我想通过创建一个新的类型 Store 来解决这个问题,该类型继承 BehaviorSubject,但确保存储的任何数据都是不可变的。

我最终得到了差不多这样的课程:

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>;
  }
}

当我尝试像这样修改对象时,会给我一个运行时错误:

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

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

然而,我也希望 TypeScript 能让开发者知道该操作是无效的,让 linter 告诉开发者他/她正在做一些非法的操作。

我该如何正确地做这件事?我是否必须以某种方式重写 Store 内的 subscribe 函数?我本希望通过在 getValue() 的返回类型上使用 Readonly 来解决问题,但上面的示例和下面的示例都没有给我任何 lint 错误:

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

我该如何确保使用 TypeScript 通知这些对象的不变性,而不仅仅是在运行时出现错误?

作为参考,deepFreeze 的实现如下:

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);
}

(基于 MDN 关于 Object.freeze 的文档)