网站搜索

关于 TypeScript 泛型,T[number][] 是否等于 T?


我正在编写一个 TypeScript 方法,该方法接受一个泛型 T,该泛型继承自一个 MySQL 结果数组。我通过一个方法进行映射,该方法返回 T 的元素的 Promise(T[number]),然后通过 Promise.all 等待它们。这应该会得到一个 T 的元素数组,T[number][],我原以为这会简化为 T。但是当我返回结果时,会出现错误 Type 'T[number][]' is not assignable to type 'T'。

我这里做错了什么?T[number][] 不等于 T 吗?

这是一个简化的 TS playground 重现。

export async function executeAllParallel<
  T extends readonly (QueryResult | Record<string | number, unknown>[])[],
>(
  dataAccountId: string,
  queries: QueryOptions[],
  retries: number = 0,
): Promise<T> {
  const connection: mysql.PoolConnection =
    await poolCluster.getConnection(dataAccountId);
  try {
    await connection.beginTransaction();

    const results: T[number][] = await Promise.all(
      queries.map((query) =>
        connection.execute<T[number]>(query).then((result) => result[0]),
      ),
    );

    await connection.commit();

    // Type 'T[number][]' is not assignable to type 'T'.
    return results;
  } catch (error) {
    await connection.rollback();
    if (retries <= 1) throw error;
    connection.release();
    return executeAllParallel(dataAccountId, queries, retries - 1);
  } finally {
    connection.release();
  }
}

答案#1

TypeScript 可以表达,我假设你正在使用元组类型。

元组类型是另一种数组类型,它确切地知道包含多少元素,以及在特定位置包含哪些类型。

作为例子,考虑这个 T:

type SpecificArray = [number, boolean, string];

这定义了一个具有正好三种特定类型元素的数组。

type T1 = T[number];

编译器所能做的最好就是推断 T1=number | boolean | string。

type T2 = T1[];

那是 (number | boolean | string)[],有关单个元素限制的信息已经丢失。

所以不,T[number][] 不会是 T。


总体而言,你的代码假设各个 queries 将返回满足对应 T 索引的类型,除非你想进一步限制 QueryOptions 的类型,否则你能做的最好的事情就是手动将 results 类型转换为 T。