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

有更好的想法吗?

【问题讨论】:

您应该将您的成员数据包装在访问函数中。然后,这些可以检查被要求添加到数组中的参数数量和/或数据长度。 你的意思是gettersetter 是的。将它们设为私有并提供方法来控制从列表中推送或删除的内容。然后你就可以完全控制它了 @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:如何在编译时声明固定大小的数组以进行类型检查的主要内容,如果未能解决你的问题,请参考以下文章

编译没有 DOM 声明的 Typescript

在调用通用处理程序(如 expressJS 中间件)时,如何让 TypeScript 编译器对方差感到满意

如何在 C# 中声明具有固定数量的固定大小字符串的数组?

TypeScript 中是不是有一种编译时方法来声明一个 keyof 类型,只有映射到特定类型的键? [复制]

如何在 C# struct 中声明和使用固定大小的字符缓冲区

急!!vb怎么创建数组?