我具有以下结构:
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”的可能值(至少在Config类中,理想情况下也在接口中),以便它们不仅是任何字符串,而且是位于BrandConfig密钥?我知道我可以在构造函数中的运行时执行此检查,但是我正在尝试将尽可能多的检查移到编译阶段,并为此提供适当的智能感知。
答案 0 :(得分:1)
您可以使用Generics和keyof/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"
,然后您将获得:
类型'“想要成为品牌”'不能分配给类型'“品牌1” | “ brand2””。
还请注意,我们使用const assertions来缩小myConfig
的推断类型。