Reputation: 420
I would like to get proper typing for accessing object properties based on provided key names. I want to get keys of object one level below.
I have following object from which I want to access some data:
const source = {
sth: {
EXAMPLE: 'this is my example'
},
another: {
TEST: 'this is my test value'
}
};
Accessing function:
function getMessage(context : keyof typeof source, msgKey: string) : string {
if(msgKey in source[context]) {
return source[context][msgKey]
}
}
By keyof typeof source
I'm getting first-level keys - works like a charm.
How to get lower level keys? With msgKey: string
of course I'm getting error:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ EXAMPLE: string; } | { TEST: string; }'. No index signature with a parameter of type 'string' was found on type '{ EXAMPLE: string; } | { TEST: string; }'
Of course, by getMessage('sth', 'EXAMPLE')
I want to get 'this is my example'
Upvotes: 0
Views: 220
Reputation: 2078
According to the compiler hint
No index signature with a parameter of type 'string' was found on type '{ EXAMPLE: string; } | { TEST: string; }'
You need to specify the index signature for the properties of source
:
interface Source {
[key: string]: { // First level
[key: string]: string; // Second level
}
}
const source: Source = {
sth: {
EXAMPLE: 'this is my example'
},
another: {
TEST: 'this is my test value'
}
};
Now you don't even need to write keyof typeof source
for the first level as it's already implied from the Source
interface:
function getMessage(context: string, msgKey: string): string {
if(msgKey in source[context]) {
return source[context][msgKey]
}
}
From my understanding, there is no way to specify index signatures for any dynamic level of nesting, so you have to specify them explicitly for each level. However, you could make things a bit easier with generics:
type Indexed<T> = {
[key: string]: T;
}
const source: Indexed<Indexed<string>> = {
sth: {
EXAMPLE: 'this is my example'
},
another: {
TEST: 'this is my test value'
}
};
Not the most elegant thing to read when your object has three or more levels of nesting but it's an option:
const source: Indexed<Indexed<Indexed<Indexed<string>>>> = {};
Upvotes: 1