【问题标题】:TypeScript: Conditionally declare the return type of a functionTypeScript:有条件地声明函数的返回类型
【发布时间】:2019-04-09 15:14:51
【问题描述】:

我正在使用 TypeScript 编写一个 React 应用程序。

我为一个调用 API 的函数编写了一个包装器:

import { ROUTE_CANDIDATES, ROUTE_TWIG_PICK } from "../../../config/constants/routes";
import { pickSchema } from "../../../config/schemas/picks";
import { PickCreateBulkResponse, PickCreateUpdateResponse } from "../../../config/types";
import { postRequest, putRequest } from "../../utils/serverRequests";

interface PickJSON {
  candidate: string;
  picked_int_choice: string;
}

const pickListSchema = [pickSchema];

export const postPickCreate = (
  body: PickJSON | PickJSON[]
): Promise<PickCreateUpdateResponse | PickCreateBulkResponse> => {
  if (Array.isArray(body)) {
    return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickListSchema) as Promise<
      PickCreateBulkResponse
    >;
  } else {
    return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickSchema) as Promise<
      PickCreateUpdateResponse
    >;
  }
};

如您所见,我正在尝试动态断言响应的正确类型。这意味着如果函数与数组一起使用,它应该返回Promise&lt;PickCreateBuldResponse&gt;,而如果它与单个对象一起使用,它应该返回Promise&lt;PickCreateUpdateResponse&gt;。我怎样才能让 TypeScript 知道它返回了什么?正如您在上面看到的,我尝试使用as,但这不起作用。

【问题讨论】:

    标签: reactjs typescript typescript-typings typescript-types


    【解决方案1】:

    你可以声明function overloads:

    export function postPickCreate(body: PickJSON): Promise<PickCreateUpdateResponse>
    export function postPickCreate(body: PickJSON[]): Promise<PickCreateBulkResponse>
    export function postPickCreate(body: PickJSON | PickJSON[]):
        Promise<PickCreateUpdateResponse | PickCreateBulkResponse> {
    
        if (Array.isArray(body)) {
            return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickListSchema) as
                Promise<PickCreateBulkResponse>;
        } else {
            return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickSchema) as
                Promise<PickCreateUpdateResponse>;
        }
    }
    

    但是,由于在您的情况下,您在设计时已经知道值的类型,并且 TypeScript 会为您进行类型检查,因此您最好的方法可能是简单地分离您的函数。这就是您在 if 块中的函数内部实际执行的操作:

    export function postPickCreate(body: PickJSON): Promise<PickCreateUpdateResponse> {
        return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickSchema) as
            Promise<PickCreateUpdateResponse>;
    }
    
    export function postPickCreateRange(body: PickJSON[]): Promise<PickCreateBulkResponse> {
        return postRequest(ROUTE_CANDIDATES + ROUTE_TWIG_PICK, body, pickListSchema) as
            Promise<PickCreateBulkResponse>;
    }
    

    【讨论】:

    • 我不认为as Promise&lt;PickCreateBulkResponse&gt;as Promise&lt;PickCreateUpdateResponse&gt; 做任何事情,可以删除它们。 (另外,函数声明的主体后没有;。)
    • @T.J.Crowder:删除了分号,谢谢。我将as Promise&lt;&gt; 与OP 的帖子保持不变,因为我不知道postRequest 到底做了什么。
    • @T.J.Crowder:谢谢 :)
    • 我们不需要知道postRequest 做了什么,但是,我们不需要那些类型断言。 :-) 重载处理。
    • @T.J.Crowder:如果postRequest 重新转换为any,我们需要相应地断言类型。
    【解决方案2】:

    您可以使用overloads 正确键入函数。

    interface Foo {}
    
    interface BarMany { many: string; }
    interface BarOne { one: string; }
    
    interface BazFunc {
        (foo: Foo[]): BarMany;
        (foo: Foo): BarOne;
    }
    
    const baz: BazFunc = (foo) => {
        if(Array.isArray(foo)) {
        return { many: "flibble" };
      } else {
          return { one: "flibble" };
      }
    };
    
    var one = baz({});
    var many = baz([]);
    

    这是一个实际的 jsFiddle:https://jsfiddle.net/z4vo5u5d/22392/

    还有输出:

    one - One: flibble, Many: undefined
    many - One: undefined, Many: flibble
    

    【讨论】:

      猜你喜欢
      • 2012-09-26
      • 2021-01-03
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 2017-12-09
      • 1970-01-01
      相关资源
      最近更新 更多