当返回类型成员具有联合类型时,从方法强制确定成员的返回类型

时间:2018-08-26 11:46:36

标签: typescript typescript-typings

通过以下方法:

private async getJobExecutionIds(): Promise<Athena.ListQueryExecutionsOutput> {
    const params = { NextToken: this.nextToken, MaxResults: 50 };
    const response = await this.athena.listQueryExecutions(params).promise();
    if (response.QueryExecutionIds instanceof Array) {
      return response;
    }
    throw new Error("No Athena QueryExecutionIds");
}

我添加了response.QueryExecutionIds instanceof Array的支票,以确保我的用户安全地依赖于QueryExecutionIds: string[] | undefined的存在

但是,当我使用此方法时:

const executionIds = await this.getJobExecutionIds();

我仍然不能依靠executionIds.QueryExecutionIds的身处string[]

如何以一种干净的方式实现这一目标?

1 个答案:

答案 0 :(得分:2)

这里的问题是,尽管打字稿具有type guards,但它不能仅基于类型来推理类型内部的属性。您需要稍微“帮助”打字稿,以了解如果response.QueryExecutionIds instanceof Array实际上是一种全新的打字稿。

因此,第一步是根据原始类型定义此新类型。在这种类型中,QueryExecutionIds不能是未定义的。这是两个选项,请选择最喜欢的选项:

type ListQueryExecutionsOutputSafe = Athena.ListQueryExecutionsOutput & {QueryExecutionIds: string[]}
interface ListQueryExecutionsOutputSafe extends Athena.ListQueryExecutionsOutput {
  QueryExecutionIds: string[];
}

下一步是定义一些自定义类型防护:

const checkIfListQueryExecutionsOutputIsSafe = (obj: Athena.ListQueryExecutionsOutput): obj is ListQueryExecutionsOutputSafe => 
  !!obj.QueryExecutionIds; 

最后:

  private async getJobExecutionIds(): Promise<ListQueryExecutionsOutputSafe> {
    const params = {NextToken: this.nextToken, MaxResults: 50};
    const response = await this.athena.listQueryExecutions(params).promise();
    if (checkIfListQueryExecutionsOutputIsSafe(response)) {
      return response;
    }
    throw new Error("No Athena QueryExecutionIds");
  }

但是为什么在这里停下来?让我们使一切通用:

type TypeWithNotNullProp<T, SafeKey extends keyof T> = T & {[K in SafeKey]-?: T[K]}

const checkSafeProp = <T, SafeKey extends keyof T>(obj: T, key: SafeKey): obj is TypeWithNotNullProp<T, SafeKey> => 
  !!obj[key];



  private async getJobExecutionIds(): Promise<ListQueryExecutionsOutputSafe> {
    const params = {NextToken: this.nextToken, MaxResults: 50};
    const response = await this.athena.listQueryExecutions(params).promise();
    if (checkSafeProp(response, 'QueryExecutionIds')) {
      return response;
    }
    throw new Error("No Athena QueryExecutionIds");
  }

我通常将TypeWithNotNullPropcheckSafeProp放在一些utils文件中,处理不同的api非常方便。