I've got a basic service and model to fetch some data looking something like this:
//api.model.ts
interface ApiErrorResponse {
hasError: boolean;
error?: {
code: number;
errorDomain: string;
description: string;
field: string;
};
}
interface ApiGetResponse<T> extends ApiErrorResponse {
response?: {
items?: T[];
};
}
//some.service.ts
import ...
interface Item {
name: string;
value: number;
}
type ItemApiResponse = ApiGetResponse<Item>;
class SomeUnNamedService {
constructor(private http: HttpClient) {
public getSomeData( userId: number): Observable<ItemApiResponse> {
this._loadingSubject.next(true);
this._errorSubject.next(false);
return this.http.post<ItemApiResponse>(
`${environment._API_}/Some/Api/EndPoint`,
{
userId
}
).pipe(
map( res => {
if(res.response?.items?.length === 0) {
this._emptySubject.next(true);
}
return res;
}),
catchError((err: ApiErrorResponse) => {
this._errorSubject.next(true);
return throwError(err);
}),
finalize(() => this._loadingSubject.next(false))
);
}
The above code works and everything is fine and dandy. However my plan is to make this pipe(?) operators(?) reusable since Im gonna use it in multiple services. So I created this, with much help from https://stackoverflow.com/a/50908353/1501643
function responseObserver<T>(thisArg) {
return pipe(
map((res: T) => {
// Property 'response' does not exist on type 'T'.
console.log(res?.response);
thisArg._emptySubject.next(true);
return res;
}),
catchError((err: ApiErrorResponse) => {
thisArg._errorSubject.next(true);
return throwError(err);
}),
finalize(() => thisArg._loadingSubject.next(false))
);
}
// I invoke it like this:
public getSomeData(
userId: string,
): Observable<ItemApiResponse> {
.....
return this.http
.post<ItemApiResponse>(
`${environment._API_}/Some/Api/Endpoint`,
{
userId
}
)
.pipe(responseObserver<ItemApiResponse>(this));
}
However as you can see the TS-compiler is complaining about 'response' does not exits... What am I missing here? Why can't the compiler interpret the generic type? Im using TypeScript 3.8
CodePudding user response:
You're making an assumption that the generic type will contain a response
property, but you haven't defined any rules to let the compiler make that assumption. Adding such a rule on your function -
function responseObserver<T extends ApiGetResponse <T>>(thisArg)
- should allow you to access response property from the generic type without compiler error because it lets the compiler know that your generic type will have properties of ApiGetResponse object, which does have a response property.