I am writing an API wrapper library in TypeScript and I want TypeScript to be able to give precise return type information based on the user inputs for an API call. I also want to transform the API response into something more usable for the library consumer.
Imagine I have an API endpoint with a return type someType
:
type someType = {
statuses?: string[], //
distances?: number[] // all arrays will be of equal length
}
Where the arrays are always of the same length and correspond to the same feature at a given index. So I would like to transform the response into an array of type someOtherType
:
type someOtherType = {
status?: string,
distance?: number
}
The user is given control over what properties are going to be on the response someType
based on an array of someType
keys. So I would like to enable TypeScript to know which properties are going to be on the returned objects and which ones aren't. I have tried the following but to no avail:
type someTypeKeys = keyof someType
type someMappedTypeKeys = keyof someOtherType
const Mapping: Record<someTypeKeys, someMappedTypeKeys> = {
statuses: "status",
distances: "distance"
}
const someObj: someType = {
statuses: ["1"],
}
type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>
type FunctionReturnType<T extends keyof someType> = Required<Pick<someOtherType, typeof Mapping[T]>>
function a<T extends (keyof someType)[]>(arg: T): Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>[] {
const someResponseObj = { // some imaginary response
statuses: ["1"],
} as unknown as Required<Pick<someType, typeof arg[number]>>
const arr: Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>[] = []
for (let i = 0; i < (someObj.statuses.length) && i ; ++i) {
const mappedObj = arg.reduce((agg, key) => {
const mappedKey = Mapping[key]
const currArr = someObj[key]
if (currArr === undefined) {
return agg
} else {
return {...agg, [mappedKey]: currArr[i]}
}
}, {}) as Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>
arr.push(mappedObj)
}
return arr;
}
const b = a(["statuses"])
b[0].distance // should be undefined
b // can I make TS be able to tell the properties available on objects in array b?