I just checked the Object.entries() typing:
/**
* Returns an array of key/values of the enumerable properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];
Option 1
It appears, you can pass the value argument type to Object.entries() explicitly. This way it regonizes the typings
const filterOptions = <T extends string>(
options: Record<T, Option>,
) => {
return Object.entries<Option>(options) // added option type here!
.map(([key, entry]) => ({
key,
...entry, // It knows for sure now..
}))
.filter(() => {
// do filtering stuff...
});
}
Option 2
The Record typings make use of symbols / numbers and strings as keys.
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
For example, this does work:
const d = Symbol('somedescripton')
const a: Record<string, Option> = {
'a': {name: 'strrst'},
b: {name:'sdfsdf'},
0: {name: 'srfsdfds'},
d: {name: 'sdfsdfd'}
}
The Object.entries() will convert it to string keys but it accepts still, Symbols and numbers aswell!!^
So for having a Record type with only string keys you would have it to type yourself for being able to omit the explicit casting:
type StringRecord<T extends string, K> = {[key in keyof T]: K }
const filterOptions = <T extends string>(
options: StringRecord<T, Option>,
) => {
return Object.entries(options)
.map(([key, entry]) => ({
key,
...entry, // works now..
}))
.filter(() => {
// do filtering stuff...
});
}