I have a function where the generic type T
(which is the fuction's return type) is a dictionary with keys of type string
and values of type unknown
(because they can be anything). I would like for the single argument that this function takes to be an object whose keys must match those of the generic type T
. This is, essentially, a function that maps an object's key/val pairs to a different set of values after some transformation work.
I'd like to use the following (note the index type in the function argument)
export function convert<T extends Record<string, unknown>, S extends keyof any>(items: {
[key: keyof typeof T]: string
}): T {
//...do stuff
return someObj as T;
}
The important thing here is keyof typeof T
. This doesn't work as I get an error:
TS2693: 'T' only refers to a type, but is being used as a value here.
I'm not sure how to remedy this, or why T
is considered a value here. Does anyone know what I'm doing wrong? The various utility types and index types that I'm using don't seem to resolve my issue. I'd like callers of the function to get warned when they try to pass objects that don't have all keys that match the type once it is defined in the implementation.
Thanks
CodePudding user response:
You have the syntax a bit wrong, a mapped type is what you want not an index signature:
export function convert<T extends Record<string, unknown>>(items: {
[key in keyof T]: string
}): T {
//...do stuff
return items as T;
}
You could also use the Record
type instead of a custom mapped type:
export function convert<T extends Record<string, unknown>>(items: Record<keyof T, string>): T {
//...do stuff
return items as T;
}
You could also map the other way around if you need to capture more info from the items
. Also I find this was more easy to understand, but the displayed type is not expanded by default:
export function convert<T extends Record<string, string>>(items: T): Record<keyof T, unknown> {
//...do stuff
return items;
}