【问题标题】:Narrow possible values of a proerty based on keys in the same object根据同一对象中的键缩小属性的可能值
【发布时间】:2020-01-01 09:35:06
【问题描述】:

我有以下结构:

export interface AppConfig {
  encryptionKey: string;
  db: TypeOrmModuleOptions;
}

export interface BrandsConfig {
  /**
   * Brand name
   */
  [key: string]: AppConfig;
}

export interface IConfig {
  brands: BrandsConfig;
  master: string;
}

export class Config implements IConfig {
  public readonly brands: BrandsConfig;
  public readonly master: string;
  public constructor(init: IConfig) {
    Object.assign(this, init);
  }
}

这个想法是 BrandsConfig 是一个键/值集合,其中值是此命名实例的设置。同时,“master”应该给这些实例中的一个(并且只有一个)一个特殊的状态。

有什么方法可以静态限制“master”的可能值(至少在 Config 类中,最好在接口中也是如此),以便它们不仅仅是任何字符串,而是位于BrandConfig 键?我知道我可以在运行时在构造函数中执行此检查,但我正在尝试将尽可能多的检查移至编译阶段,并为其提供适当的智能感知。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用Genericskeyof/Index Type Query operator 来做到这一点。

    1.) 将泛型类型参数 B 添加到您的 Config 类,可以分配给/扩展 BrandConfig:

    export class Config<B extends BrandsConfig> implements IConfig<B> {
      public readonly brands: B;
    
      public readonly master: keyof B;
    
      public constructor(init: IConfig<B>) {
        // Make it compile. Feel free to replace it by delegates, getters,etc.
        this.brands = init.brands;
        this.master = init.master;
      }
    }
    

    2.) 同样在IConfig 中添加一个对应的泛型类型参数,这样我们就可以将master 定义为一个依赖于您在BrandsConfig 中的键的键:

    export interface IConfig<B extends BrandsConfig> {
      brands: B;
      master: keyof B;
    }
    

    让我们测试客户端。如果我们为master 传递了错误的键,我们预计会出现错误。

    const myConfig = {
      brands: {
        brand1: { encryptionKey: "", db: {} },
        brand2: { encryptionKey: "", db: {} }
      },
      master: "brand1"
    } as const
    
    const config = new Config(myConfig); // works!
    

    现在将您的主属性更改为master: "Wanna be a brand",然后您将获得:

    类型“想成为一个品牌”不能分配给类型“brand1”| “品牌2”'。

    另外请注意,我们使用const assertions 来缩小myConfig 的推断类型。

    Playground

    【讨论】:

      猜你喜欢
      • 2020-12-28
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-09
      相关资源
      最近更新 更多