Let's say we have a type
type Foo = {
a: string;
b: number;
c: boolean;
}
I now want to define a type for an object having a key and a value of a given type T, so that the type of the value is directly inferred from the key, so that I can do:
const kv1: KeyValue<Foo> = {key: 'a', value: 'STRING'};
const kv2: KeyValue<Foo> = {key: 'b', value: 42};
const kv3: KeyValue<Foo> = {key: 'c', value: true};
If I simply do this:
type KeyValue<T> = {
key: keyof T;
value: T[keyof T]
}
... then obviously the values will be the union of all properties' values in Foo:
And if I do this:
type KeyValue<T, K extends keyof T> = {
key: K;
value: T[K]
}
... then sure, if explicitly typed as KeyValue<Foo, 'a'> I can create object literals that match the type of Foo:s properties, but if I don't specifically provide the type AND the key for each literal but simply do KeyValue<Foo, keyof Foo>, each value will be allowed to be of the type of any of the values in Foo, i.e., all values will be string | number | boolean instead of being inferred from the entered key.
In the end I want to be able to do things like this:
const kvs: Array<KeyValue<Foo>> = [
{key: 'a', value: 'STRING'}, // should not compile if value is a number or boolean
{key: 'b', value: 42}, // should not compile if value is a string or boolean
{key: 'c', value: true}, // should not compile if value is a string or number
];
Is it possible to derive the KeyValue type with these constraints, so that effectively it becomes KeyValue<Foo, 'a'> | KeyValue<Foo, 'b'> | KeyValue<Foo, 'c'> in the second example above, without having to manually write this union? Basically I guess what I'd like is to be able to infer the type of value from the value of key in the current literal object.