In the following example, I'm able to extract explicit keys from the object, but i'm unable to enforce its values
const myCollection = {
a: {test: 1},
b: {test: 2},
c: {text: 3} // no error
};
type MyCollectionKeys = keyof typeof myCollection;
// MyCollectionKeys is 'a' | 'b' | 'c'
When enforcing the values using the following snippet, you lose explicit keys:
type CollectionValue = {test: number};
const myCollection: ({[k: string]: CollectionValue}) = {
a: {test: 1},
b: {test: 2},
c: {text: 3} // Type '{ text: number; }' is not assignable to type 'CollectionValue'.
};
type MyCollectionKeys = keyof typeof myCollection;
// MyCollectionKeys is string | number
A workaround I found is to proxy the object like so:
type CollectionValue = {test: number};
const _myCollection = {
a: {test: 1},
b: {test: 2},
c: {text: 3}
};
type MyCollectionKeys = keyof typeof _myCollection;
// MyCollectionKeys is 'a' | 'b' | 'c'
const myCollection: ({[k in MyCollectionKeys]: CollectionValue}) = _myCollection;
// Type '{ a: { test: number; }; b: { test: number; }; c: { text: number; }; }' is not assignable to type '{ a: CollectionValue; b: CollectionValue; c: CollectionValue; }'.
// Types of property 'c' are incompatible.
// Property 'test' is missing in type '{ text: number; }' but required in type 'CollectionValue'
The drawbacks of this method are:
- you must have a proxy object
- if you violate the type, the error is thrown at the assignment instead of being thrown inside the original object at the offending key
Is there a more elegant solution for this?