typescript - 有没有办法从不同长度的元组的联合中提取带有类型的最后一个元素?

标签 typescript

我举了一个例子here .

我有许多不同长度的元组,它们都以相同的类型序列结尾。

type T1 = [number, string, number[]];
type T2 = [number, number, string, number[]];
type T3 = [number, number, number, string, number[]];

给定一个作为这些类型的联合的对象,我知道最后一个元素的类型,我什至可以让 typescript 为我推断出这些类型,但我找不到一种方法让 typescript 当我从元组中提取元素时弄清楚:

function doesnt_work(arg: T1|T2|T3) : [string, number[]] {
  return [arg[arg.length-2], arg[arg.length-1]];
}

请注意,ts 确实知道 arg[0] 的类型为 number,arg[1] 的类型为 number|string。我希望找到一种方法让它弄清楚 arg[arg.length-1] 的类型(或 arg.pop() 或 arg.slice(-1) 等)。

我尝试了arg[arg.length-n]arg.slice(-n)arg.pop()等。

我希望 typescript 能够推断类型,因为它知道元组最后一个元素的类型是什么。但它只是推断类型,就好像我用未知数字索引了元组一样。

最佳答案

TypeScript 目前没有为tuple types相对索引提供强类型。 .
有这样的东西 leading rest elements in tuple types喜欢 [...unknown[], string, number[]] ,但这只是让表示 T1 | T2 | T3 的父类(super class)型变得容易;它不会为您提供 arg[arg.length - 2] 的强类型输入。它对函数的调用者比对实现更有帮助。

您没有从 arg[arg.length - 2] 获得强类型因为 arg.length - 2 的类型只是 number ;没有对数字 literal types 的类型级操作的内置支持,按照长期未决问题 microsoft/TypeScript#26382 中的要求。即使有一天情况发生变化,拥有 T1 | T2 | T3union仍然可能会做坏事,因为 arg.length - 2将被评估为 1 | 2 | 3这与 arg 的类型不相关(参见ms/TS#30581)。所以这可能是一个死胡同。


microsoft/TypeScript#47660 有一个功能请求调用 the at() array method 时给出强类型指数为负,但因“太复杂”而被拒绝。

虽然您可以尝试自己这样做,但缺乏对数字文字类型算术的支持意味着您必须跳过一些丑陋的圈子,如 in this comment 所示。 :

type Reverse<T extends readonly any[], U extends any[] = []> =
  T extends readonly [infer F, ...infer R] ? Reverse<R, [F, ...U]> : U

type At<T extends readonly any[], I extends number> =
  `${I}` extends `-${infer J}` ? [never, ...Reverse<T>] extends
  infer R ? J extends keyof R ? R[J] :
  undefined : never : T[I]

interface ReadonlyArray<T> {
  at<I extends number>(index: I): At<this, I>;
}
interface Array<T> {
  at<I extends number>(index: I): At<this, I>;
}

适用于您的示例代码:

function f(arg: T1 | T2 | T3): [string, number[]] {
  const penultimate = arg.at(-2) // string
  const ultimate = arg.at(-1) // number[]
  return [penultimate, ultimate]; // okay
}

但这可能比它的值(value)更麻烦,特别是因为毫无疑问存在许多边缘情况,并且您必须自己维护它。如果 TS 团队认为它太复杂而无法在原生 TS 库中提供,那么您可能应该避免在自己的代码库中这样做,除非您有充分的理由。


所以目前在 TypeScript 中是不可能的,至少目前是这样。您不妨只使用 type assertions喜欢 arg[arg.length-2] as stringarg[arg.length-1] as number[]并继续前进。

Playground link to code

关于typescript - 有没有办法从不同长度的元组的联合中提取带有类型的最后一个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77029133/

相关文章:

javascript - 您可能需要一个合适的加载器来处理这种文件类型。 Angular4-Firebase 表达式预期错误

typescript - 使用 typescript 的 Angular 6 的黄金布局?

typescript - 找不到带有 typescript 和 deno 的名称

javascript - 在嵌套对象函数中键入 this

node.js - 使用导入时,TypeScript 将无法解析模块

css - Angular Material *ngFor 在 <mat-cell> 内用于搜索

javascript - 未选中复选框时如何在javascript中执行弹出操作?

TypeScript:区分元组中的联合和值

javascript - 构建 react 应用程序的版本,提供指向 CSS 和 JS 文件的错误链接

将接口(interface)或类型分配给 Record<string, string> 的 typescript