TypeScript:如何在编译时声明固定大小的数组以进行类型检查
Posted
技术标签:
【中文标题】TypeScript:如何在编译时声明固定大小的数组以进行类型检查【英文标题】:TypeScript: how to declare array of fixed size for type checking at Compile Time 【发布时间】:2017-07-15 10:46:29 【问题描述】:更新:这些检查适用于编译时,而不是运行时。在我的示例中,失败的案例都在编译时被捕获,我期望其他 should-fail 案例的行为类似。
假设我正在编写一个类似表格的类,我希望该类的所有成员都是相同长度的数组,例如:
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
到目前为止我找到的最接近的解决方案是:
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
有更好的想法吗?
【问题讨论】:
您应该将您的成员数据包装在访问函数中。然后,这些可以检查被要求添加到数组中的参数数量和/或数据长度。 你的意思是getter
和setter
?
是的。将它们设为私有并提供方法来控制从列表中推送或删除的内容。然后你就可以完全控制它了
@iberbeu 如果我理解正确,这会在 runtime 提供检查,对吗? 编译时间呢?就像 C/C++ 中的方式一样。
目前不可能,但有一个提议:github.com/Microsoft/TypeScript/issues/6229
【参考方案1】:
这是一个控制其内部数组长度的类的简单示例。它不是万无一失的(在获取/设置时,您可能需要考虑您是浅/深克隆等:
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
);
【讨论】:
感谢您的回答,但正如您在问题下的讨论中看到的那样,我打算在编译时而不是运行时执行此检查。我正在更新问题以避免将来出现混淆。【参考方案2】:更新 2:从 3.4 版开始,OP 要求的内容现在完全可以通过简洁的语法 (Playground link):
class MyClass
tableHead: readonly [string, string, string]
tableCells: readonly [number, number, number]
更新 1:从 2.7 版开始,TypeScript 现在可以distinguish between lists of different sizes。
我认为不可能对元组的长度进行类型检查。 Here 是 TypeScript 的作者对此主题的看法。
我认为您的要求是不必要的。假设你定义了这个类型
type StringTriplet = [string, string, string]
并定义该类型的变量:
const a: StringTriplet = ['a', 'b', 'c']
你不能从那个三元组中得到更多的变量,例如
const [one, two, three, four] = a;
将给出错误,而这与预期不同:
const [one, two, three] = a;
我认为缺乏限制长度的能力成为问题的唯一情况是,例如当你map
超过三元组时
const result = a.map(/* some pure function */)
并期望 result
有 3 个元素,而实际上它可以有 3 个以上。但是,在这种情况下,您将 a
视为集合而不是元组,因此这不是正确的用例元组语法。
【讨论】:
好答案。我喜欢你包含 Hejlsberg 的评论,有助于了解背景。【参考方案3】:来自Typescript: Can I define an n-length tuple type?,以编程方式,具有动态长度:
type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & length: TLength ;
type Tuple9<T> = Tuple<T, 9>;
【讨论】:
如果这个硬编码的 9 需要是动态的怎么办。换句话说,给定 2 个元组,我希望第二个元组与第一个元组一样长。 从类型的角度来看,我认为这是最有活力的。也许您过于复杂了,只需要旧的数组类型: MyThing[] ?以上是关于TypeScript:如何在编译时声明固定大小的数组以进行类型检查的主要内容,如果未能解决你的问题,请参考以下文章
在调用通用处理程序(如 expressJS 中间件)时,如何让 TypeScript 编译器对方差感到满意
TypeScript 中是不是有一种编译时方法来声明一个 keyof 类型,只有映射到特定类型的键? [复制]