I want to create a base class for working with API (let's call it BaseAPI). Then, for each API, create a wrapper like UsersAPI, LoginAPI and such. So base class only encapsulates logic for making HTTP requests and aligning responses to same structure.
Minimal example:
type BaseResp = Record<string, unknown>
class BaseAPI {
async get(url: string): Promise<BaseResp> {
const resp = await fetch(url)
return await resp.json()
}
}
interface LoginResp extends BaseResp {
username: string
}
class AuthAPI extends BaseAPI {
async login(): Promise<LoginResp> {
return await this.get("/login")
}
}
The problem is that in fact BaseApi.get returns a Promise<any>, cause I don't know what data comes from the backend, so it's any.
But I know how server responds to /login API calls, so I want to receive typed object (LoginResp) after awaiting AuthAPI.login.
My linter is set up the way that it doesn't allow any usage, and I don't want to suppress it.
That's why I tried to follow TS conventions and replace any with Record<string, unknown>.
Now I'm getting an error: Property 'username' is missing in type 'Promise<BaseResp>' but required in type 'LoginResp'.(2741)
How to set up typing correctly?