网站搜索

typescript - 元组返回类型与输入元组长度相同,如果输入是数组,则返回数组


我想将一个函数的返回类型设置为一个元组,其长度等于参数数组的长度,如果在构建时已知长度的话。否则,返回类型应该是一个布尔数组。

第一部分可以正常工作,然而当长度在构建时未知时,类型是一个没有任何类型的空元组。

type Tuple<
  T,
  Length extends number,
  Accumulator extends T[] = [],
> = Accumulator["length"] extends Length
  ? Accumulator
  : Tuple<T, Length, [...Accumulator, T]>;

function useHasPermissions<
  const T extends {
    schemaName: string;
    action: string;
  }[],
>(args: { permissions: T }): Tuple<boolean, T["length"]> {
  return [] as any;
}

使用元组调用(长度在构建时已知):

// const tup: [boolean, boolean, boolean]
const tup = useHasPermissions({
  permissions: [
    {
      schemaName: "User",
      action: "read",
    },
    {
      schemaName: "User",
      action: "create",
    },
    {
      schemaName: "User",
      action: "update",
    },
  ],
});

使用动态数组的调用(构建时长度未知):

const arr = useHasPermissions({
  permissions: getAtRuntime(),
});

// Tuple type '[]' of length '0' has no element at index '0'.ts(2493)
// Should be: boolean[]
const a = arr[0];

答案#1

如果你有一个输入数组类型,并且想要生成一个具有相同一般形状但元素类型不同的输出数组类型,你可以简单地使用映射类型。映射类型会自动从(泛型)数组类型生成数组类型,从元组类型生成元组类型。对于你的例子,它看起来像这样:

export function useHasPermissions<
  const T extends {
    schemaName: string;
    action: string;
  }[],
>(args: { permissions: T }): { [I in keyof T]: boolean } {
  return [] as any;
}

然后它就按预期工作了:

const tup = useHasPermissions({
  permissions: [
    { schemaName: "User", action: "read", },
    { schemaName: "User", action: "create", },
    { schemaName: "User", action: "update", },
  ]
});
// const tup: [boolean, boolean, boolean]

const arr = useHasPermissions({
  permissions:
    getAtRuntime(),
});
// const arr: boolean[]

代码的 Playground 链接