Reputation: 3
Im pretty new to Typescript and I've gotten stuck and im trying to understand if this is possible.
My goal is to be able to call my function "getRecords" with a specifc option property called "fields" where I input the fields I want to fetch from my server, and I want typescript to suggest the fieldnames I used for the input on the object that gets returned.
I have been trying to do this with a single field as an input but my ultimate goal is to use an array with field names.
Here is an example code, I also created a typescript playground:
const getRecords = async (options: { fields: string }): Promise<{ result: { [options.fields]: string}[] } | undefined> => {
return await new Promise((resolve, reject) => {
//Fetch Something here
resolve({
result: [
{ name: 'Test Name' }
]
})
reject(undefined)
})
}
const test = async () => {
let data = await getRecords({
fields: 'name'
})
console.log(data)
}
test()
The only time I got it to work was when I hardcoded the key in the returning promise like this:
Promise<{ result: { ['name']: string}[] } | undefined>
Would really appreciate any help with this
Thanks!
Upvotes: 0
Views: 1529
Reputation: 9248
Something like this will do what I think you're after:
const makeKeys = <T extends string>(fields: T[]): Record<T, string> => {
// Sample implementation
const map: Record<T, string> = {} as Record<T, string>
for (const field of fields) {
map[field] = 'test value';
}
return map;
}
const obj = makeKeys(['test', 'thing']);
// These fields can now be safely accessed with autocomplete :)
obj.thing // string
obj.test // string
The key things here are we specify that we're passing an array of strings to the function
<T extends string>(fields: T[])
and that the function will return a Record type whose keys are the very same strings contained in the array
Record<T, string>
Once TS knows that the type system can infer that whichever strings you've passed into the input array will be the keys of the output object.
// These fields can now be safely accessed with autocomplete :)
obj.thing // string
obj.test // string
Upvotes: 1