首页 > 解决方案 > 如何使用类型检查设置对象属性,但在更改时触发函数

问题描述

我有一个看起来像这样的类:

export class Settings {
 public controls: SettingControls {
    toolbarOpen: false,
    awaitingHttpResponse: false,
    selectedTab: TabOption.NOTIFICATIONS,
    selectedTheme: ThemeOption.DARK
    // etc. (the actual amount of controls is much longer)
  };
}

我想检测何时对controls属性进行更改并用可观察的方式宣布它。目前我用一个简单的setControl函数来做(并将_controls属性设置为私有):

setControl(key, value) {
  this._controls[key] = value;
  this._updatedSetting.next({key, value}); // Announce the change
}

这有效,但这意味着没有检查值的类型。我已经研究过动态生成 getter 和 setter(像这样),但不幸的是,这并没有帮助。我可以为每个属性分别写出一个 getter/setting,但我想避免这种情况。

标签: typescript

解决方案


您可以通过安装访问器(getter/setter)来做到这一点,正如您已经说过的。当您尝试为控件对象(具有 SettingsControl 类型)的属性分配值时,将执行 typescript 的类型检查。看看下面的代码,当一个值被分配给控件对象的任何属性并进行类型检查时,它会调用 fireControlUpdated。

请注意,您应该在每次添加/删除控件对象的属性时调用 installAccessors() 以使其正常工作。

enum ENUM1 {
    val1,
    val2,
}

enum ENUM2 {
    val1,
    val2,
}

interface SettingsControls {
    toolbarOpen: boolean,
        awaitingHttpResponse: boolean,
        selectedTab: ENUM1,
        selectedTheme: ENUM2
}

class Settings {
    private _controls = {};
    public controls: SettingsControls = {
        toolbarOpen: false,
        awaitingHttpResponse: false,
        selectedTab: ENUM1.val2,
        selectedTheme: ENUM2.val1
    };

    constructor() {
        this.installAccessors();
    }

    installAccessors() {
        for (let key in this.controls) {
            if (this.controls.hasOwnProperty(key)) {
                Object.defineProperty(this.controls, key, {
                    get: () => { return this._controls[key]; },
                    set: (v: any) => {
                        console.log(this);
                        this._controls[key] = v;
                        this.fireControlUpdated(key, v);
                    }
                });
            }
        }
    }

    fireControlUpdated(key: string, v: any) {
      console.log(`key ${key}: new value: ${v}`)
    }
}

let a = new Settings();

a.controls.toolbarOpen = true;

// the following will produce typescript compile error because 
// the type of the selectedTab is ENUM1

// a.controls.selectedTab = ENUM2.val1;

// this one works
a.controls.selectedTab = ENUM1.val2;

console.log("toolbarOpen is: " + a.controls.toolbarOpen);
console.log("selectedTab is: " + ENUM1[a.controls.selectedTab]);

推荐阅读