首页 > 解决方案 > 如何在打字稿中编写一个泛型函数,其中两个参数的参数为​​ value 或 value []

问题描述

我正在尝试创建一个通用函数,它将接受一个字符串 hasMapName 和另一个参数键作为字符串 | string[] 和一个将返回 T | 的回调 T[]。

如果键是字符串,回调应该返回 T,如果键是 String[],它应该返回 T[]。

尝试了以下代码:


    export function getData<K extends string | string[], T>(
      hashMapName: string,
      keys: K extends string[] ? string[] : string,
      serviceCallBack: K extends string[] ? () => Promise<T[]> : () => Promise<T>
    ): Promise<T> {
      return Array.isArray(keys)
        ? getDataForKeys<T>(hashMapName, keys, serviceCallBack)
        : getDataForKey<T>(hashMapName, keys, serviceCallBack);
    }

但是我在 getDataForKey 中的键处遇到 tserror。

错误:

Argument of type 'K extends string[] ? string[] : string' is not assignable to parameter of type 'string'.
  Type 'string | string[]' is not assignable to type 'string'.
    Type 'string[]' is not assignable to type 'string'.
      Type 'string | string[]' is not assignable to type 'string'.
        Type 'string[]' is not assignable to type 'string'.

更新1:

请找到 getDataForKeys 和 getDataForKey 函数的声明。


    declare function getDataForKey<T>(
      hashMapName: string,
      key: string,
      serviceCallBack: () => Promise<T>
    )

    declare function getDataForKeys<T>(
      hashMapName: string,
      key: string[],
      serviceCallBack: () => Promise<T[]>
    )

由于我们严格遵守 noExplicitAny 政策,我们将无法对功能参数使用任何关键字。

尝试@Dmitriy 答案后,现在面临以下问题。

Argument of type '(() => Promise<T[]>) | (() => Promise<T>)' is not assignable to parameter of type '() => Promise<T[]>'.
  Type '() => Promise<T>' is not assignable to type '() => Promise<T[]>'.
    Type 'Promise<T>' is not assignable to type 'Promise<T[]>'.
      Type 'T' is not assignable to type 'T[]'

标签: javascripttypescriptgenericsecmascript-6

解决方案


对于这个用例,您应该使用重载函数而不是条件类型:

declare function getDataForKey<T>(...args: any[]): Promise<T>;
declare function getDataForKeys<T>(...args: any[]): Promise<T[]>;


export function getData<T>(
  hashMapName: string,
  keys: string,
  serviceCallBack: () => Promise<T>
): Promise<T>
export function getData<T>(
  hashMapName: string,
  keys: string[],
  serviceCallBack: () => Promise<T[]>
): Promise<T[]>
export function getData<T>(
  hashMapName: string,
  keys: string | string[],
  serviceCallBack: (() => Promise<T[]>) | (() => Promise<T>)
): Promise<T> | Promise<T[]> {
  return Array.isArray(keys)
    ? getDataForKeys<T>(hashMapName, keys, serviceCallBack)
    : getDataForKey<T>(hashMapName, keys, serviceCallBack);
}

getData("foo", "fooo", async () => "bar"); // works
getData("foo", ["fooo"], async () => ["bar"]); // works

getData("foo", ["fooo"], async () => "bar"); // error

// also works because T is not constrained to be non-array
getData("foo", "fooo", async () => ["bar"]); 


推荐阅读