Итак, вы хотите, чтобы 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
без необходимости переопределения его с нуля.
Удачи снова.