推断剩余元组类型中的泛型参数

infer generic parameters in rest tuple type

正在阅读 rest elements in tuple types 并试图找出如何提取类型的通用部分:

type Attribute<Type> = { id: string, type?: Type };

type Position = { x: number, y: number };
let Position: Attribute<Position> = { id: "position" };

type Status = "active" | "inactive";
let Status: Attribute<Status> = { id: "status" };

我确定有一种方法可以编写条件类型,将各种 Attribute<T> 的元组映射到各种 T.

的元组
type AttributeTypes<Attributes extends Attribute<any>[]> =
   Attributes extends Attribute<infer T> ? T[] : never;

type Result = AttributeTypes<[typeof Position, typeof Status]> // should be `[Position, Status]`

但我对推理步骤的理解不够深入,它总是在 never 分支中结束。

最后一步是编写一个使用推断类型作为 return (Playground) 一部分的函数:

function getAll<Attributes extends Attribute<any>[]>(
  ...attributes: Attributes
): AttributeTypes<Attributes> {
  return attributes.map(attribute => attribute.type);
}

let [position, status]: [Position, Status] = getAll(Position, Status);

条件类型没有理由在元组上工作,你的条件类型基本上解决了问题 [typeof Position, typeof Status] extends Attribute<infer T>,但它显然没有,所以你最终得到了 never。

您可以将联合传递给类型 (AttributeTypes<typeof Position | typeof Status>),然后您将得到 Position[] | Status[],这并不是您真正想要的 (Play)

您也可以在条件类型中使用数组 (Attributes extends Array<Attribute<infer T>> ? T[] : never),但这不会保留输入中的元组结构 (Play)

获得所需输出的最佳方法是使用映射类型。映射类型保留元组,同时允许您将元组的每个元素类型映射到结果元组中的新元素类型:

type Attribute<Type> = { id: string, type?: Type };

type Position = { x: number, y: number };
let Position: Attribute<Position> = { id: "position" };

type Status = "active" | "inactive";
let Status: Attribute<Status> = { id: "status" };

type AttributeTypes<Attributes extends Attribute<any>[]> = {
  [P in keyof Attributes]: Attributes[P] extends Attribute<infer T> ? T : never;
}

type Result = AttributeTypes<[typeof Position, typeof Status]> // is [Position, Status]

Play