如何在子类(typescript)中正确键入返回值
我想创建一个使用API的基类(我们称之为如何在子类(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扩
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)}`)
}
}