2

我目前正在实现一个类似数组的打字稿类。有没有办法计算 TypeScript 中索引签名对象中的项目数?该类具有成员函数和属性,但应该可以通过索引签名访问。有以下设置

export class MyIndexedClass {
  [index: number] : number;
  anotherProp = 'hello';

  get length() {
    // Object.keys returns an array of all properties as strings
    return Object.keys(this).length;
  }
}

我想获得没有所有静态项(函数和字符串属性)的索引项的长度。也许过滤数字键可以解决问题,但这似乎容易出错,我无法想象有更智能的方法。

return Object.keys(this)
    .filter(o => !isNaN(parseInt(o, 10)))
    .length;

这真的很hacky,我根本不喜欢这种方法。对此有何想法或建议?谢谢,干杯!

4

1 回答 1

1

所以你想要的length东西就像{0: "first", 100: "last"}2而不是101,对吧?也就是说,稀疏数组length之类的值预计会小于您从其属性中获得的值。没有内置方法可以为您做到这一点,因此过滤属性可能是最简单的方法。length

假设是这样:

“数字”键(如您所知实际上是字符串)的更好过滤器是这样的:

Object.keys(this).filter(k => (""+(+k))===k).length

过滤器将密钥强制转换为数字,然后返回字符串......如果它在往返过程中毫发无损,那么该密钥与数字键无法区分。否则,它不是真正的“数字”键,您将无法使用数字索引访问该属性。例如:

const obj: { [k: number]: string | undefined } = {};
obj[1] = "A";
console.log(JSON.stringify(obj)); // {"1":"A"} 
obj[+1] = "B";
console.log(JSON.stringify(obj)); // {"1":"B"}
obj["1"] = "C";
console.log(JSON.stringify(obj)); // {"1":"C"} 
obj["+1"] = "D"; 
console.log(JSON.stringify(obj)); // {"1":"C","+1":"D"}

console.log(Object.keys(obj).filter(o => !isNaN(parseInt(o, 10)))); 
// Array [ "1", "+1" ]

console.log(Object.keys(obj).filter(k => ("" + (+k)) === k));
// Array [ "1" ]

即使数值与数值1相同+1,字符串值"1"也不同于字符串值"+1"。该对象obj在键处具有属性,"1""+1"您只能使用"1"数字索引访问该属性。

请注意,数字索引也不会将您限制为非负整数键。以下所有内容在 TypeScript 和 JavaScript 中都很好:

obj[1.5] = "E";
obj[-2] = "F";
obj[Infinity] = "G";
obj[NaN] = "H";
obj[1.23e100] = "I";

其中大多数未通过parseInt()测试,但通过了我给出的过滤器。同样,类似的键"23 skidoo"会通过我给出的过滤器但通过parseInt()测试。


无论如何,希望这会有所帮助。祝你好运!


更新:由于您希望它更像一个实际数组,因此该length属性应始终大于最高数字 index。看起来一个数组只关心与小于某个值的非负整数相对应的数字兼容索引(可能是 2^32)。您可以通过以下方式获得类似的行为:

  get length() {
    return Math.max(-1, ...Object.keys(this).filter(
      k => ("" + (+k)) === k // numeric keys
    ).map(
      k => +k // as numbers
    ).filter(
      n => isFinite(n) && n >= 0 && n === Math.round(n) // non-neg integers
        && n < 4294967296 // less than 2^32
    )) + 1;
  }

你可以简化一点,但我认为它或多或少是你正在寻找的东西。

如果您宁愿从不同的角度来解决整个问题,您可以使您的类实例 aProxy代表数字索引访问和length真正的数组。或者更好的是,您可以使您的类成为其自身的子类Array以继承的行为,length而无需从头开始重新实现它。

再次祝你好运。

于 2019-02-01T20:08:17.920 回答