如何在子类(typescript)中正确键入返回值

如何在子类(typescript)中正确键入返回值,typescript,types,Typescript,Types,我想创建一个使用API的基类(我们称之为BaseAPI)。然后,为每个API创建一个包装器,如UsersAPI、LoginAPI等。所以基类只封装了用于发出HTTP请求和将响应与相同结构对齐的逻辑 最简单的例子: type BaseResp=记录 类BaseAPI{ 异步获取(url:string):承诺{ const resp=等待获取(url) return wait resp.json() } } 接口LoginResp扩展了BaseResp{ 用户名:string } 类AuthAPI扩

我想创建一个使用API的基类(我们称之为
BaseAPI
)。然后,为每个API创建一个包装器,如
UsersAPI
LoginAPI
等。所以基类只封装了用于发出HTTP请求和将响应与相同结构对齐的逻辑

最简单的例子:

type BaseResp=记录
类BaseAPI{
异步获取(url:string):承诺{
const resp=等待获取(url)
return wait resp.json()
}
}
接口LoginResp扩展了BaseResp{
用户名:string
}
类AuthAPI扩展了BaseAPI{
异步登录():承诺{
返回等待。获取(“/login”)
}
}
问题是,实际上
BaseApi.get
返回了一个
承诺
,因为我不知道什么数据来自后端,所以它是
any

但我知道服务器如何响应
/login
API调用,所以我希望在等待
AuthAPI.login
之后接收类型化对象(
LoginResp

我的linter设置为不允许使用
任何
,我不想抑制它。
这就是为什么我试图遵循TS惯例,用
Record
替换
any

现在我得到一个错误:
属性“username”在类型“Promise”中丢失,但在类型“LoginResp”中是必需的。(2741)


如何正确设置键入?

由于json原始解析的结果总是
任何
(它的类型无法在编译时确定),因此您有两个选择

1。您信任从服务器返回的内容。

在这种情况下,您可以强制转换已解析的json数据,您可以将
BaseApi
类型修改为如下内容:

class BaseAPI {
    async get<T extends BaseResp>(url: string): Promise<T> {
        const resp = await fetch(url)
        return await resp.json() as T
    }
}
在保持其余代码不变的同时,您可以更改
AuthApi
类:

class AuthAPI extends BaseAPI {
    async login(): Promise<LoginResp> {
        const response = await this.get("/login")
        if (isLoginResp(response)) {
          return response
        }
        throw new TypeError(`Expected LoginResp, got ${JSON.stringify(response)}`)
    }
}
类AuthAPI扩展了BaseAPI{ 异步登录():承诺{ const response=wait this.get(“/login”) if(isLoginResp(响应)){ 返回响应 } 抛出新的TypeError(`Expected LoginResp,got${JSON.stringify(response)}`) } }
嘿!谢谢你的回答,至少我已经尝试了第一种选择,而且成功了。你能解释一下
get
符号的含义吗?或者至少它是如何命名的,以便我可以阅读文档?@fbjorn当然,这里您可以阅读更多关于它的信息:。在这种情况下,这意味着您的函数将有一个泛型参数
T
,并且
T
类型对它有一个约束,因此它至少应该具有
BaseResp
的属性。当您调用函数时,您也可以这样调用它:
this.get(…)
,更准确地说,但是类型是推断出来的。
class AuthAPI extends BaseAPI {
    async login(): Promise<LoginResp> {
        const response = await this.get("/login")
        if (isLoginResp(response)) {
          return response
        }
        throw new TypeError(`Expected LoginResp, got ${JSON.stringify(response)}`)
    }
}