我举了一个here的例子.

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

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

给出一个由这些类型组成的对象,我知道最后一个元素的类型(S),我甚至可以让TypeScrip为我推断这些类型,但当我从元组中提取元素时,我找不到一种方法让TypeScrip来计算它:

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

请注意,ts确实知道arg[0]具有类型编号,而arg[1]具有类型编号|字符串.我希望找到一种方法,让它计算出arg[arg.length-1]的类型(或arg.op(),或arg.Slice(-1)等).

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

我希望类型脚本能够推断类型,因为它知道元组的最后一个元素的类型.但它只是推断类型,就像我用未知数索引元组一样.

推荐答案

TypeScript doesn't currently give strong types for relative indexing into tuple types.
There is such a thing as leading rest elements in tuple types like [...unknown[], string, number[]], but this just makes it easy to represent a supertype of T1 | T2 | T3; it doesn't give you strong typings for arg[arg.length - 2]. It's more helpful to callers of your function than to the implementation.

您不能从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时给出强类型,但被拒绝了,理由是"太复杂".

虽然您可以自己使用try来完成此操作,但由于缺乏对数字文字类型算术的支持,您必须跳过一些难看的圈套,如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
}

但这可能比它的价值更麻烦,特别是因为毫无疑问有很多边缘情况,你必须自己维护它.如果TS团队认为它太复杂,无法在原生TS库中提供,您可能应该避免为您自己的代码库这样做,除非您有非常好的理由.


因此,目前还不能用Typescript ,至少目前是这样.你不妨使用type assertions,就像arg[arg.length-2] as stringarg[arg.length-1] as number[]一样,然后继续前进.

Playground link to code

Typescript相关问答推荐

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

如何正确修复TypScript 4.7到4.8升级中的TS 2345编译错误

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

为什么从数组中删除一个值会删除打字错误?

从typescript中的对象数组中获取对象的值作为类型'

APIslice-CreateAPI的RTK打字错误

如何判断对象是否有重叠的叶子并产生有用的错误消息

如何使默认导出与CommonJS兼容

根据类型脚本中的泛型属性 Select 类型

Typescript 中相同类型的不同结果

抽象类对派生类强制不同的构造函数签名

如何为特定参数定义子路由?

如何在try 运行独立的文字脚本Angular 项目时修复Visual Studio中的MODULE_NOT_FOUND

创建一个函数,该函数返回一个行为方式与传入函数相同的函数

为什么TypeScrip假定{...省略类型,缺少类型,...选取类型,添加&>}为省略类型,缺少类型?

对于VUE3,错误XX不存在于从不存在的类型上意味着什么?

如何避免多个类型参数重复?

我可以使用JsDocs来澄清Typescript实用程序类型吗?

在Typescript 无法正常工作的 Three.js 中更新动画中的 GLSL 统一变量

为什么 typescript 在对象合并期间无法判断无效键?