TypeScript: Exact key value pairs
If you create an object like this, although the keys are correctly inferred, all of the values will be of type string
.
const obj = {
FOO: 'FOO', // FOO: string
BAR: 'BAR', // BAR: string
};
This means that even though you are only allowing access to certain keys, you cannot ensure that the values exactly match these keys.
You can easily fix this by defining a type for the key values, which we can use to enforce key value pairs that match.
type KeyValue = 'FOO' | 'BAR';
You can then use this to define the exact keys and values in an object.
const exactObj: {[K in KeyValue]: K} = {
FOO: 'FOO', // FOO: 'FOO'
BAR: 'BAR', // BAR: 'BAR'
};
We can also define this inline so that we don’t need the extra type definition.
const exactObj: {[K in 'FOO' | 'BAR']: K} = {
FOO: 'FOO', // FOO: 'FOO'
BAR: 'BAR', // BAR: 'BAR'
};
Or, more sensibly, we could create a generic type that we can use to define multiple key value pairs.
type KeyValuePairs<T extends string> = {[K in T]: K};
const exactObj: KeyValuePairs<'FOO' | 'BAR'> = {
FOO: 'FOO', // FOO: 'FOO'
BAR: 'BAR', // BAR: 'BAR'
};
Again, we could also have 'FOO' | 'BAR'
defined as its own type, as we’ll likely need to refer to these values elsewhere.