背景
我在想,是否有可能在TypeScript中创建一个类型,允许安全地将配置与允许的值进行Map。
假设我有下面的接口,它作为某个配置节点的定义:
interface CategoryDefinition {
property1: string,
actions: { [key: string]: string }
}
以及实现该接口的实际配置(通常可以是从文件加载的JSON,该示例只是为了更好地说明问题):
const definitions: { [key: string]: CategoryDefinition } = {
key1: {
property1: "PROPERTY_NAME_1",
actions: {
action1: "ACTION_1",
action2: "ACTION_2"
}
},
key2: {
property1: "PROPERTY_NAME_2",
actions: {
action3: "ACTION_3",
action4: "ACTION_4"
}
},
// etc...
};
配置被Map到内部具有其他方法的对象,因此CategoryDefinition
中的每个action
都有一个来自父对象的property1
,如下所示:
class ConfigValue {
private propertyName: string;
private action: string;
constructor(category: string, action: string) {
this.category = category;
this.action = action;
}
methondOne(): void { /* doesn't really matter what's inside */}
}
问题
我想在配置对象/ hashmap中保留这样的Map对象,该对象具有来自上一示例的definitions
的键,并且每个对象都具有来自嵌套在其中的Category.action
对象的键。
export const configMapped /*: TypeImLookingFor */ = {
key1: {
action1: ConfigValue("PROPERTY_NAME_1", "ACTION_1"),
action2: ConfigValue("PROPERTY_NAME_1", "ACTION_2"),
},
key2: {
action3: ConfigValue("PROPERTY_NAME_2", "ACTION_3"),
action4: ConfigValue("PROPERTY_NAME_2", "ACTION_4"),
},
}
**我应该使用什么类型来确保这些actions
属于在上一步中定义的有限有效键集?**我的目标是按以下方式使用此配置:
// valid call, `action1` is valid key for `key1`
configMapped.key1.action1.methodOne();
// invalid call
configMapped.key1.action4;
这在TypeScript中有可能吗?它不一定是复杂类型,它可以是相互关联的不同类型的集合。
感谢您的帮助和宝贵意见!
1条答案
按热度按时间vxf3dgd41#
你应该能够使用Map类型来获得你想要的行为。下面是我如何编写Map的:
然后,对于一个 * 足够具体的 *
definitions
,你可以写这可能是答案的结尾,但我在评论中提到了一个问题,你 * 不能 * 做你在这里做的事情:
如果你显式地将definitions变量注解为
{ [key: string]: CategoryDefinition }
类型,那么你实际上已经丢弃了编译器可能拥有的关于分配给它的特定键和子键的任何信息,编译器说:“好吧,我所知道的关于badDefinitions
的所有信息就是它的所有属性都是CategoryDefinition
”。如果尝试将
MapConfig
应用于 that,丢失的信息仍然会丢失,并且您会得到可能的最通用类型:ConfigValue
s的未指定字典的未指定字典:所以你需要备份并让编译器推断
definitions
的类型。如果你是用你问题中的玩具例子做的,这是没有问题的,只要留下注解:或者,如果您最终关心的是属性的确切字符串值,则可能使用
const
Assert(在本问题中您不会关心,但在真实的代码中可能会关心):如果从静态JSON文件导入,可以使用
--resolveJsonModule
,但不能使用as const
(请参见microsoft/TypeScript#32063了解其特性请求)。如果在代码编译之后通过fetch加载它,则什么也做不了;编译器在你的JS运行的时候已经过时了,除非你事先知道确切的键和属性,否则你不能使用类型注解,如果你知道的话,你还不如使用静态资源,而不是获取任何东西。
假设这只是内联代码,我们让编译器推断
definitions
的类型,然后您可以验证MappedDefinitions
是否计算为所需的类型:并使用它,
为您提供基于键名允许/禁止属性访问所需的类型信息:
Playground链接