Start learning free

LESSON 98 OF 348 · ARRAYS I

Exceeding Array Bounds in TypeScript: Fixing the Buggy Code

Lesson Read the full explanation

When accessing array data with indices, the most common problem we can run into is exceeding the array's bounds.

Remember, the items of an array are indexed from 0 to length - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, TypeScript doesn't throw an error, but simply returns undefined:

let myArray = [1, 2, 3];

// Valid indices: 0, 1, 2
console.log(myArray[0]); // Output: 1
console.log(myArray[2]); // Output: 3

// Invalid indices: 3, 30, -1
console.log(myArray[3]); // Output: undefined
console.log(myArray[30]); // Output: undefined
console.log(myArray[-1]); // Output: undefined

As programmers, we always want to make sure that we don't exceed one array's bounds in our programs


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    TYPESCRIPT · ARRAYS I

    Exceeding Array Bounds in TypeScript, explained

    What the code is supposed to do

    The program has an array ages with four numbers and should print its last element, 21. When you run the starting code, it prints undefined instead:

    let ages: number[] = [14, 32, 50, 21];
    
    console.log(ages[ages.length]);
    

    No error appears, no red text, and the program finishes normally. That silence is what makes this bug easy to miss.

    What goes wrong

    Array indices start at 0. An array with four elements stores them at indices 0, 1, 2 and 3:

    Index0123
    Value14325021

    The property ages.length counts the elements, so it is 4. The code therefore reads ages[4], one position past the last element. Nothing is stored there.

    In many languages that mistake stops the program with an exception. JavaScript, and so TypeScript, behaves differently: reading a missing index gives the value undefined and the program carries on. The line prints undefined, which looks like a normal result.

    Why the compiler doesn't help

    The type annotation number[] says every element is a number, and nothing about how many elements there are. By default, the compiler types ages[ages.length] as a plain number, so it reports no error even though the value at run time is undefined. Types are erased when the code is compiled to JavaScript, so they can't check indices while the program runs. The index is your responsibility.

    Fixing it step by step

    1. Find the valid range. For ages the indices are 0 to 3, which is 0 to ages.length - 1.
    2. Pick the right index. The last element is the one at the top of that range, ages.length - 1.
    3. Subtract 1 inside the brackets. The expression ages.length - 1 is evaluated first and gives 3, so the access becomes ages[3].

    The fixed code in TypeScript

    let ages: number[] = [14, 32, 50, 21];
    
    console.log(ages[ages.length - 1]);
    

    This prints 21. Writing ages[3] would print the same here, but ages[ages.length - 1] keeps working when the array grows or shrinks.

    Other ways to go out of bounds

    An index is invalid when it is below 0 or above length - 1. All of these give undefined:

    let ages: number[] = [14, 32, 50, 21];
    
    console.log(ages[4]);   // undefined
    console.log(ages[30]);  // undefined
    console.log(ages[-1]);  // undefined
    

    The case ages[-1] catches people who expect it to mean "the last item", as it does in some other languages. In TypeScript it is just a lookup for something that isn't there. If you want counting from the end, ages.at(-1) returns 21 here, and the lesson's length - 1 form does the same job.

    The same thing happens in loops. A loop written as for (let i = 0; i <= ages.length; i++) uses <=, so it runs once more than it should and its last pass reads ages[4]. The correct condition is i < ages.length.

    Why undefined is dangerous

    The problem often shows up later than the bad read. The value undefined spreads through the program without an error until something uses it:

    let ages: number[] = [14, 32, 50, 21];
    
    let last: number = ages[ages.length];
    console.log(last + 1); // NaN
    

    Here the arithmetic gives NaN ("not a number") instead of stopping. Reading a property such as last.toFixed(1) would throw a TypeError, but far from the line that caused it. Finding the cause is easier if you remember to check the index where the value is read.

    Common mistakes

    • Using length as the last index. The last index is length - 1.
    • Subtracting too much. ages[ages.length - 2] is the second to last element, which is 50.
    • Empty arrays. For [], length - 1 is -1, so even the fixed line prints undefined. Check ages.length > 0 first when the array may be empty.
    • Trusting the absence of an error. A program that prints undefined ran fine as far as JavaScript is concerned, so check the output, not only whether the program crashed.

    Checking your fix

    A quick way to test an index is to print the whole array next to it, so you can count positions yourself: console.log(ages, ages.length) shows the four values and the number 4.

    Edit the line in the editor above and run it. A correct fix prints 21. If it still prints undefined, the index is still outside the range 0 to 3.

    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free