Reputation: 15
i try to create correct typings for situations, when trying to map the array of objects to array with the same objects but using the property value as index key..
interface ValueDefinition {
name: string;
}
function getByName<V extends ValueDefinition>(valuDefinitions: V[]) {
let out = {}
for (const key in valuDefinitions) {
out[valuDefinitions[key].name] = valuDefinitions[key];
}
return out;
}
const obj: ValueDefinition = {
name: 'super'
};
const objKey = getByName([
obj
]);
key.super; // Typings for this output
I looking for something like this:
type WithKey<D extends ValueDefinition> = {
[key: D['name']]: D;
}
Thanks.
Upvotes: 1
Views: 4088
Reputation: 330086
You should make your ValueDefinition
interface generic in the string literal type of the name
property, so you can extract it later:
interface ValueDefinition<K extends string = string> {
name: K
}
Then you can represent the output of your getByName()
function as the following mapped type:
type ValueDefinitionObject<K extends string> = {[P in K]: ValueDefinition<P>}
And revise the signature of getByName
to be generic in the set of 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;
}
At this point it will work, but you have to be careful to declare your obj
so that the type of the value 'super'
is inferred as 'super'
and not string
. This identity function will help:
function asValueDefinition<K extends string>(vd: ValueDefinition<K>): ValueDefinition<K> {
return vd;
}
Okay, let's try it (with another one I'm adding):
const obj = asValueDefinition({ name: 'super' });
const obj2 = asValueDefinition({ name: 'thing' });
If you inspect them they show up as ValueDefinition<'super'>
and ValueDefinition<'thing'>
.
const objKey = getByName([obj, obj2]);
And objKey
is typed as ValueDefinitionObject<'super'|'thing'>
. Let's use it:
objKey.super; // okay, ValueDefinition<'super'>
objKey.thing; // okay, ValueDefinition<'thing'>
objKey.nope; // error, property 'nope' doesn't exist
Does that work for you? Good luck!
Upvotes: 4