Числовой индекс подписи машинописный класс, получить количество элементов или доступ в целом - PullRequest
0 голосов
/ 01 февраля 2019

В настоящее время я реализую класс-подобный машинописный класс.Есть ли способ подсчитать количество элементов в индексированном объекте подписи в 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;
  }
}

Я хочу получить длину проиндексированных элементов без всех статических элементов (функций и строковых свойств).Может быть, фильтрация по числовым ключам поможет, но это может привести к ошибкам, и я не могу представить, что есть более разумный подход.подойти вообще.Есть идеи или предложения по этому поводу?Спасибо, ура!

1 Ответ

0 голосов
/ 01 февраля 2019

Итак, вы хотите, чтобы 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 должно всегда быть больше самого высокого числового индекса .Похоже, массив специально заботится только о числово-совместимых индексах, которые соответствуют неотрицательным целым числам, меньшим некоторого значения (возможно, 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;
  }

Вы можете немного упростить это, но я думаю, это более или менее то, что вы ищете.

Если вы предпочитаете рассматривать эту проблему с другой стороны, вы можете сделать экземпляры вашего класса Proxy, который делегирует обращения к числовому индексу, и length в реальном массиве.Или, может быть, лучше, вы можете сделать свой класс подклассом Array самого , чтобы унаследовать поведение length без необходимости переопределения его с нуля.

Удачи снова.

...