TypeScript:如何在编译时声明固定大小的数组以进行类型检查
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42441408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TypeScript: how to declare array of fixed size for type checking at Compile Time
提问by benjaminz
Update: These checks are meant for compile time, not at runtime. In my example, the failed cases are all caught at compile time, and I'm expecting similar behaviour for the other should-failcases.
更新:这些检查用于编译时,而不是运行时。在我的示例中,失败的案例都是在编译时捕获的,我期待其他应该失败的案例有类似的行为。
Suppose I'm writing a table-like class where I want all members of the class to be arrays of the same length, something like:
假设我正在编写一个类似表格的类,我希望该类的所有成员都是相同长度的数组,例如:
class MyClass {
tableHead: string[3]; // expect to be a 3 element array of strings
tableCells: number[3]; // expect to be a 3 element array of numbers
}
The closest solution I've found so far is:
到目前为止,我找到的最接近的解决方案是:
class MyClass {
tableHead: [string, string, string];
tableCells: [number, number, number];
}
let bar = new MyClass();
bar.tableHead = ['a', 'b', 'c']; // pass
bar.tableHead = ['a', 'b']; // fail
bar.tableHead = ['a', 'b', 1]; // fail
// BUT these also pass, which are expected to fail at compile time
bar.tableHead = ['a', 'b', 'c', 'd', 'e']; // pass
bar.push('d'); // pass
bar.push('e'); // pass
Any better ideas?
有什么更好的想法吗?
回答by Huy Nguyen
Update 2: From version 3.4, what the OP asked for is now fully possible with a succinct syntax (Playground link):
更新 2:从 3.4 版开始,OP 要求的内容现在完全可以通过简洁的语法(Playground 链接)实现:
class MyClass {
tableHead: readonly [string, string, string]
tableCells: readonly [number, number, number]
}
Update 1: From version 2.7, TypeScript can now distinguish between lists of different sizes.
更新 1:从 2.7 版开始,TypeScript 现在可以区分不同大小的列表。
I don't think it's possible to type-check the length of a tuple. Here's the opinion of TypeScript's author on this subject.
我认为不可能对元组的长度进行类型检查。这是 TypeScript 作者对这个主题的看法。
I'd argue that what you're asking for is not necessary. Suppose you define this type
我认为你所要求的不是必需的。假设你定义了这个类型
type StringTriplet = [string, string, string]
and define a variable of that type:
并定义该类型的变量:
const a: StringTriplet = ['a', 'b', 'c']
You can't get more variables out of that triplet e.g.
你不能从那个三元组中得到更多的变量,例如
const [one, two, three, four] = a;
will give an error whereas this doesn't as expected:
将给出错误,而这不符合预期:
const [one, two, three] = a;
The only situation where I think the lack of ability to constrain the length becomes a problem is e.g. when you map
over the triplet
我认为缺乏限制长度的能力成为问题的唯一情况是例如当你map
超过三元组时
const result = a.map(/* some pure function */)
and expect that result
have 3 elements when in fact it can have more than 3. However, in this case, you are treating a
as a collection instead of a tuple anyway so that's not a correct use case for the tuple syntax.
并期望result
有 3 个元素,而实际上它可以有 3 个以上。但是,在这种情况下,您无论如何都将其a
视为集合而不是元组,因此这不是元组语法的正确用例。
回答by cancerbero
From Typescript: Can I define an n-length tuple type?, programmatically, with dynamic length:
来自打字稿:我可以定义一个 n 长度的元组类型吗?,以编程方式,具有动态长度:
type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };
type Tuple9<T> = Tuple<T, 9>;
回答by Chris Cousins
Here is a simple example of a class to control the length of its internal array. It isn't fool-proof (when getting/setting you may want to consider whether you are shallow/deep cloning etc:
这是一个控制其内部数组长度的类的简单示例。这不是万无一失的(在获取/设置时,您可能需要考虑是否进行浅/深克隆等:
https://jsfiddle.net/904d9jhc/
https://jsfiddle.net/904d9jhc/
class ControlledArray {
constructor(num) {
this.a = Array(num).fill(0); // Creates new array and fills it with zeros
}
set(arr) {
if (!(arr instanceof Array) || arr.length != this.a.length) {
return false;
}
this.a = arr.slice();
return true;
}
get() {
return this.a.slice();
}
}
$( document ).ready(function($) {
var m = new ControlledArray(3);
alert(m.set('vera')); // fail
alert(m.set(['vera', 'chuck', 'dave'])); // pass
alert(m.get()); // gets copy of controlled array
});