打字稿数组推送方法无法捕获数组的元组类型

seo*_*han 8 javascript typescript

const testArray:[number, string] = [10, 'test', 's'];
Run Code Online (Sandbox Code Playgroud)

它不起作用。

const testArray:[number, string] = [10, 'test']; // It's been edited.
testArray.push('test');
Run Code Online (Sandbox Code Playgroud)

有用。

我认为第二个代码不应该工作。
为什么第二个代码有效?这是一个错误吗?


-添加-

我一直在思考这个问题。
编译器只能在编译时捕获错误。所以编译器不会捕捉到错误。这样对吗?

jca*_*alz 11

这是一个很好的问题,我将尝试尽可能明确地重新表述它:

元组类型是一种长度已知的数组类型,其中不同的元素可能具有不同的类型。type 的[number, string]值保证有一个lengthof 2,一个numberat 元素0和一个stringat 元素1

那么,为什么 TypeScript 允许您在元组类型的值上调用诸如push()pop()shift()unshift()和 之splice()类的方法,而这些方法通常会破坏元组类型的假定保证?难道不应该阻止你这样做,就像它阻止你指定的值等[1, "two", "three"][number, string]摆在首位?

是的,这不是很好。

我不知道对此有一个很好的规范答案。我能找到的最接近的是microsoft/TypeScript#6325,它建议从元组类型中省略此类方法。该提议被拒绝,可能的理由是这将是对现有现实世界代码的重大更改

建议的替代方案看起来像

type StrictTuple<T extends any[]> =
    Omit<T, keyof (any[])> extends infer O ? { [K in keyof O]: O[K] } : never;
Run Code Online (Sandbox Code Playgroud)

它看起来不像一个数组,而更像是一组数字键属性:

const x: StrictTuple<[number, string]> = [1, ""] // {0: number; 1: string }
x[1] = "okay";
x[0] = 123;
x.push(123); // error!
//~~~~ Property 'push' does not exist on type { 0: number; 1: string; }
Run Code Online (Sandbox Code Playgroud)

如果你真的关心这些事情,你可能想使用StrictTuple上面的东西,但这可能比它的价值更麻烦。元组类型在 TypeScript 中无处不在,如果您使用无法分配给它们的表单,那么您将不得不跳过很多不幸的环节才能使用 TypeScript。

务实地说,我想说的是尽量不要改变元组。

这是可能的,有人可能会打开一个新的问题,引用微软/打字稿#6325问现在重新考虑这一点,元组都变得有点在这段时间更严格。看看如果push/ pop/etc 从元组类型中省略,具体会中断什么将是一个有趣的练习。

Playground 链接到代码


Kai*_*ter 8

[删除之前的答案,因为我误解了。]

看起来这可能是与类型扩展相关的问题?您可以将元组声明为readonlyas const阻止推送函数在元组上工作

const testArray:readonly [number, string] = [10, 'test'] as const;
testArray.push('test') // error
Run Code Online (Sandbox Code Playgroud)

我发现这篇关于该主题的中等文章:https://blog.logrocket.com/const-assertions-are-the-killer-new-typescript-feature-b73451f35802/