To ensure flexibility, consider making your ValueDefinition
interface generic by specifying the string literal type of the name
property:
interface ValueDefinition<K extends string = string> {
name: K
}
You can then define the output of the getByName()
function using a mapped type:
type ValueDefinitionObject<K extends string> = {[P in K]: ValueDefinition<P>}
Adjust the signature of the getByName
function to encompass various name
literals:
function getByName<K extends string>(valuDefinitions: Array<ValueDefinition<K>>): ValueDefinitionObject<K> {
let out = {} as ValueDefinitionObject<K>
for (const key in valuDefinitions) {
out[valuDefinitions[key].name] = valuDefinitions[key];
}
return out;
}
Ensure proper typing when declaring your obj
, so that values like 'super'
are inferred correctly with an identity function:
function asValueDefinition<K extends string>(vd: ValueDefinition<K>): ValueDefinition<K> {
return vd;
}
Now you can test it out by creating instances of the objects:
const obj = asValueDefinition({ name: 'super' });
const obj2 = asValueDefinition({ name: 'thing' });
Inspecting them reveals types like ValueDefinition<'super'>
and ValueDefinition<'thing'>
.
const objKey = getByName([obj, obj2]);
objKey
is now typed as
ValueDefinitionObject<'super'|'thing'>
. Let's utilize it:
objKey.super; // returns ValueDefinition<'super'>
objKey.thing; // returns ValueDefinition<'thing'>
objKey.nope; // error, property 'nope' does not exist
Give it a try! Good luck!