I would like to define a mapped type whose keys are the values of all constants under a namespace.
I wasn't able to find other questions that cover this. 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.
Description:
I have a namespace as such:
export namespace Controls {
export const Foo = "foo";
export const Bar = "bar";
export const Baz = "baz";
// ... a dozen others
}
This namespace contains nothing else. Only those exported const
s.
I would like to define an object type to express the following meaning: "this object keys can only be const values declared in that namespace". Naively something like:
type Namespaced = { [K in Controls]?: ControlDelegate }
The above doesn't compile because I can't use a namespace as a type. Indexing the type also doesn't work for the same reason:
type NamespaceKeys = Controls[keyof typeof Controls]
Then I had this epiphany to use:
{ [K in keyof typeof Controls]?: ControlDelegate }
which does compile, and the resolved type looks like what I want, however I'm then unable to instantiate literals:
this.controlDelegates = {
[Controls.Foo]: new FooControlDelegate() // it implements ControlDelegate
}
with the following compile error:
Type '{ "foo": FooControlDelegate; }' is not assignable to type '{ readonly Foo?: ControlDelegate; ... Object literal may only specify known properties
What's the correct way to constrain the type of object keys to the values under a certain namespace?
keyof typeof Controls
gives you the keys of Controls
, which are "Foo", "Bar", "Baz". What you want are the values of Controls
which are "foo", "bar", "baz" (lowercase).
You can achieve this with typeof Controls[keyof typeof Controls]
.