如何将对象键的类型限制为命名空间常量?
How to constrain type of object keys to namespace constants?
我想定义一个映射类型,其键是命名空间下所有常量的值。
我找不到涵盖此问题的其他问题。 This question and its duplicate talk about JavaScript, whereas I'm looking to strongly type the property of a class. I also couldn't find a reference in the Typescript handbook.
描述:
我有这样的命名空间:
export namespace Controls {
export const Foo = "foo";
export const Bar = "bar";
export const Baz = "baz";
// ... a dozen others
}
此命名空间不包含任何其他内容。仅导出 const
s.
我想定义一个对象类型来表达以下含义:“此对象键只能是在该命名空间中声明的常量值”。天真地像:
type Namespaced = { [K in Controls]?: ControlDelegate }
以上无法编译,因为我不能将名称空间用作类型。出于同样的原因,索引类型也不起作用:
type NamespaceKeys = Controls[keyof typeof Controls]
然后我有了这个顿悟可以用:
{ [K in keyof typeof Controls]?: ControlDelegate }
确实可以编译,并且解析后的类型看起来像我想要的,但是我无法实例化文字:
this.controlDelegates = {
[Controls.Foo]: new FooControlDelegate() // it implements ControlDelegate
}
编译错误如下:
Type '{ "foo": FooControlDelegate; }' is not assignable to type '{ readonly Foo?: ControlDelegate; ... Object literal may only specify known properties
将对象键的类型限制为特定命名空间下的值的正确方法是什么?
keyof typeof Controls
为您提供 Controls
的 键 ,它们是“Foo”、“Bar”、“Baz”。您想要的是 Controls
的 values,即“foo”、“bar”、“baz”(小写)。
您可以通过 typeof Controls[keyof typeof Controls]
实现。
感谢@cdimitroulas 的建议,我最终将 属性 声明为:
controlDelegates: { [K in typeof Controls[keyof typeof Controls]]?: ControlsDelegate }
然后可以正确初始化为:
this.controlDelegates = {
[Controls.Foo]: new FooControlDelegate()
}
但是,这种方法无法扩展。下一次将某物添加到命名空间时,如果该某物具有不可分配给对象键的类型——例如a class — 打字会中断。
由于命名空间只包含字符串常量,一个更具前瞻性的解决方案是将其转换为 enum
:
export enum Controls {
FOO = "foo";
BAR = "bar";
BAZ = "baz";
// ... and so on
}
我想定义一个映射类型,其键是命名空间下所有常量的值。
我找不到涵盖此问题的其他问题。 This question and its duplicate talk about JavaScript, whereas I'm looking to strongly type the property of a class. I also couldn't find a reference in the Typescript handbook.
描述:
我有这样的命名空间:
export namespace Controls {
export const Foo = "foo";
export const Bar = "bar";
export const Baz = "baz";
// ... a dozen others
}
此命名空间不包含任何其他内容。仅导出 const
s.
我想定义一个对象类型来表达以下含义:“此对象键只能是在该命名空间中声明的常量值”。天真地像:
type Namespaced = { [K in Controls]?: ControlDelegate }
以上无法编译,因为我不能将名称空间用作类型。出于同样的原因,索引类型也不起作用:
type NamespaceKeys = Controls[keyof typeof Controls]
然后我有了这个顿悟可以用:
{ [K in keyof typeof Controls]?: ControlDelegate }
确实可以编译,并且解析后的类型看起来像我想要的,但是我无法实例化文字:
this.controlDelegates = {
[Controls.Foo]: new FooControlDelegate() // it implements ControlDelegate
}
编译错误如下:
Type '{ "foo": FooControlDelegate; }' is not assignable to type '{ readonly Foo?: ControlDelegate; ... Object literal may only specify known properties
将对象键的类型限制为特定命名空间下的值的正确方法是什么?
keyof typeof Controls
为您提供 Controls
的 键 ,它们是“Foo”、“Bar”、“Baz”。您想要的是 Controls
的 values,即“foo”、“bar”、“baz”(小写)。
您可以通过 typeof Controls[keyof typeof Controls]
实现。
感谢@cdimitroulas 的建议,我最终将 属性 声明为:
controlDelegates: { [K in typeof Controls[keyof typeof Controls]]?: ControlsDelegate }
然后可以正确初始化为:
this.controlDelegates = {
[Controls.Foo]: new FooControlDelegate()
}
但是,这种方法无法扩展。下一次将某物添加到命名空间时,如果该某物具有不可分配给对象键的类型——例如a class — 打字会中断。
由于命名空间只包含字符串常量,一个更具前瞻性的解决方案是将其转换为 enum
:
export enum Controls {
FOO = "foo";
BAR = "bar";
BAZ = "baz";
// ... and so on
}