I have a function which fetches data and optionally transforms the response to another interface.
I'm having trouble expressing this in Typescript though:
type ObjMap = Record<string, any>;
function mapResponse<T extends ObjMap, U extends ObjMap = T>(
apiData: T,
transform: (apiModel: T) => U = x => x
) {
return transform(apiData)
}
// Should return AppUser
const data1 = mapResponse<ApiUser, AppUser>(
userData,
u => ({ fullName: `${u.firstName} ${u.lastName}`})
)
// Should return ApiUser
const data2 = mapResponse<ApiUser>(userData)
The above code produces an error here:
x => x
~~
Type 'T' is not assignable to type 'U'.
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'ObjMap'.(2322)
How can I type this so that the
- Return type is
ApiUser
if no transform is defined (we can just use the default transformx => x
, or none if that's easier) - Returns
ApiUser
if thetransform
is defined?
CodePudding user response:
One option is to have an implementation signature that is not generic. here ou can specify the default value for the parameter:
function mapResponse<T extends ObjMap, U extends ObjMap = T>(
apiData: T,
transform?: (apiModel: T) => U
):U
function mapResponse(
apiData: Record<string, any>,
transform: (apiModel: Record<string, any>) => Record<string, any> = x => x
) {
return transform(apiData)
}
CodePudding user response:
Something like this might be the answer... I simplified your code for ease of reproduction.
function mapResponse<T>(apiData: T): T
function mapResponse<T, U>(apiData: T, transform: (apiModel: T) => U): U
function mapResponse<T, U = T>(
apiData: T,
transform?: (apiModel: T) => U
): T | U {
const trans = transform ?? (x => x as unknown as U)
throw Error()
}
The implementation might get messy, but the interface to the outside world is consistent.