【问题标题】:Fixing types in Typescript修复 Typescript 中的类型
【发布时间】:2020-02-19 00:01:48
【问题描述】:

我有一个使用来自外部 API 的数据的方法:

public async getStatus(id: string): Promise<APIRes | undefined> {
    try {
        const result = await getRequest(`${this.URL}/endpoint/${id}`)
        const response: APIRes = result.data

        return response
    } catch (err) {
        errorHandler(err)
    }
}

APIRes 的界面如下:

export interface APIRes{
version: string,
status: string,
uuid: string,
time: string

}

问题是当我尝试从另一个方法调用 getStatus 时:

public async getListOfResults(id: string) {
        try {

            const getStatus = await this.getStatus(id)
            if (getStatus.status === 'Queue' || getStatus.status === 'Progr') {
                ...//MORE CODE
            }

            const result = await getRequest(`${this.URL}/endpoint/${id}/result`)

            return result.data
        } catch (err) {
            errorHandler(err)
        }
    }

我在 getStatus.status 上收到 Object is possibly undefined。现在我明白为什么会发生这种情况(因为 getStatus 方法可能返回未定义),但不确定如何在不添加 nostrict 标志的情况下最好地修复。

如果我在getStatus 的返回类型中删除&lt;| undefined&gt;,我会得到

Function lacks ending return statement and return type does not include 'undefined'.ts(2366)`

如果我尝试将其从 undefined 更改为 void,我仍然会在 getStatus.status 上收到错误

【问题讨论】:

  • 如果await this.getStatus(id) 产生undefined,你想在运行时发生什么?
  • 我希望这会产生错误
  • 那么在const getStatus = ...之后和if (getStatus.status ...之前写if (!getStatus) throw new Error("THE WORLD HAS ENDED");什么的,这样编译器就知道getStatus肯定会被定义。
  • 您是说它返回 APIRes 类型的承诺或未定义的承诺? Promise&lt;APIRes | undefined&gt; 我想你的意思是它要么返回一个 APIRes 类型的 Promise,要么只返回 undefined,对吧?
  • 您应该考虑将此处的代码设置为真正的minimal reproducible example,可以将其放入任何IDE,其中唯一的错误就是您要询问的错误。然后有人可以通过确保示例代码按预期工作来知道他们已经回答了这个问题。祝你好运!

标签: javascript typescript ecmascript-6 types


【解决方案1】:

您很可能会看到此错误,因为您在 tsconfig.xml 中将 TypeScript 设置为 strict 模式。这会启用另一个标志 strictNullChecks,这反过来又会强制类型 anyundefined 只能分配给它们自己,因为您可以阅读 here

在您的代码中,getStatus 的签名是public async getStatus(id: string): Promise&lt;APIRes | undefined&gt;,因此返回的类型可以是Promise&lt;undefined&gt;,这意味着您必须检查它是否未定义。

public async getListOfResults(id: string) {
        try {

            const getStatus = await this.getStatus(id)
            if (getStatus // Check if getStatus is NOT undefined before accessing it's properties (so it can only be Promise<APIRes>)
                && (getStatus.status === 'Queue' || getStatus.status === 'Progr')) {
                ...//MORE CODE
            }

            const result = await getRequest(`${this.URL}/endpoint/${id}/result`)

            return result.data
        } catch (err) {
            errorHandler(err)
        }
    }

【讨论】:

    【解决方案2】:

    这种方法让你的事情变得比你需要的更困难。如果getStatus 出现错误,您是否想要将其解析为undefined?如果是这样,那么调用它的所有东西都必须检查那个未定义的。为什么不让调用者寻找抛出的错误呢?只需让错误冒泡,或者执行错误处理程序并重新抛出:

    public async getStatus(id: string): Promise<APIRes> {
        try {
            const result = await getRequest(`${this.URL}/endpoint/${id}`)
            const response: APIRes = result.data
    
            return response
        } catch (err) {
            errorHandler(err)
            throw err;
        }
    }
    

    现在,这将解析为APIRes,您不必处理undefined 的情况。你只需要确保有东西能捕捉到错误。

    【讨论】:

    • 这似乎是一个更好的方法!
    • 我的 errorHandler 方法已经在做一些类似于 throw new Error(there was an error with your req) 的事情。如果我添加额外的throw err 是否意味着它会抛出两次?
    • errorHandler 的类型是什么?除非它是 never 类型,否则 TypeScript 可能不知道调用它总是会抛出异常。
    • 不过,要回答您的问题,如果 errorHandler 已经抛出,那么您的 throw err; 行将无法到达,因此它不会抛出两次。如果 TS 不够聪明,无法弄清楚 errorHandler 正在做什么,那么添加额外的 throw 语句不会有任何害处,而且会是一种有效的解决方法。
    猜你喜欢
    • 2022-08-16
    • 2018-07-24
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    • 2019-03-02
    • 2021-04-19
    • 2021-11-26
    • 2020-03-04
    相关资源
    最近更新 更多