Utilizing TypeScript's noUncheckedIndexedAccess for secure array access

I'm currently investigating the reasons behind TypeScript allowing array access in the first scenario mentioned below, but not in the second. Despite having noUncheckedIndexedAccess enabled, I am ensuring that the accessed objects are not undefined before accessing them.

For example, this code snippet does not produce an error:

const arr: number[][] = [[], [], []];
if (arr[0] != undefined) {  
    arr[0][0] = 42;  
}

However, this code snippet does result in an error:

function twoDimArrayAccess(arr: number[][], x: number, y: number) {
    if (arr[x] != undefined) {
        arr[x][y] = 1;
        ^^^^^^ 
        // TS2532: Object is possibly undefined

    }
}

Answer №1

Short Version: Your code is compatible with TypeScript 5.5 and higher thanks to the implementation of control flow narrowing for constant indexed accesses as described in microsoft/TypeScript#57847.


In TypeScript, narrowing has been possible for dot property indexed accesses, like the example below:

const val: { a?: { b: string } | undefined } = { a: { b: "" } };
if (val.a) {
    val.a.b = "x"
}

However, this wasn't the case for bracket property indexed access, as shown here:

const arr: ({ b: string } | undefined)[] = [{ b: "" }];
if (arr[0] != undefined) {
    arr[0].b = "x"
}  

Initially, bracket indexed narrowing was not supported for variables, only for literal types like 0.

In the past, users had to employ workarounds like saving accessed values to variables to achieve narrowing. Thankfully, TypeScript 5.5 addresses this issue and eliminates the need for such workarounds.


If you are still using TypeScript 5.4 or lower, consider updating to 5.5 for seamless bracket property indexed access narrowing.

Click here to try the code on TypeScript Playground

Answer №2

Enabling the setting noUncheckedIndexedAccess to true in Typescript signifies that the possibility of array access going out of bounds is always considered. As a result, your array type will be interpreted as:

((number | undefined)[] | undefined)[]

When accessing arr[x], it may return a value that is potentially undefined (xxx | undefined). Due to the intricacies in tracking changes to elements within arrays, Typescript is unable to definitively determine whether the array arr has been modified between the checks of if (arr[x]) and the actual access of arr[x]. Therefore, it cannot confidently assert that arr[x] is not undefined.

In cases where a constant or literal value like arr[0] is passed in, Typescript assumes that this value remains unchanged after if (arr[0]), which may not always hold true. An example where this oversight can lead to runtime errors is shown below:

const arr: number[][] = [[], [], []];
if (arr[0]) {
  arr.length = 0;   
  arr[0][0] = 42; // Cannot set properties of undefined (setting '0') 
}

Regardless of whether Typescript assumes the presence of undefined or not, its judgement is not foolproof. Hence, it tends to provide a more conservative estimate, leading to the current behavior.

If you are confident that your array accesses will not exceed bounds, the use of ! (arr[x]![y]) can be employed to bypass compile-time linting.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When running `npm test`, Mocha TS tests encounter failure, but the issue does not arise when executing them

When running tests in my Typescript nodejs project, I use the following command: mocha --compilers ts:ts-node/register,tsx:ts-node/register The tests run successfully with this command. However, when I try to run them using npm test, I encounter the foll ...

Combining and mapping arrays in Javascript to form a single object

I am using the following firebase function this.sensorService.getTest() .snapshotChanges() .pipe( map(actions => actions.map(a => ({ [a.payload.key]: a.payload.val() }))) ).subscribe(sensors => { ...

Retrieving Vue component properties as a data type

I'm facing a dilemma with my Vue components. I want to extract the props from one component and use them as a type instead of a value in another component. Specifically, I have a component where I need to take in an array of props from a different com ...

What is the best way to define a type for a variable within a function, depending on the type of an argument passed to that function in Typescript?

As I delve into developing a custom useFetch composable for a Vue application, the focus seems to shift towards TypeScript. Essentially, my query revolves around conditionally asserting a type to a variable within a function, contingent on the type of an a ...

Exploring Cypress: Iterating over a collection of elements

I have a small code snippet that retrieves an array of checkboxes or checkbox labels using cy.get in my Angular application. When looping through the array to click on each element and check the checkboxes, it works fine if the array contains only one elem ...

Provide a string argument when instantiating an abstract class

I am searching for a method to assign a name string within a class and utilize it in the abstract class at the constructor level, without the need for a function. Opening up the constructor is not an option due to using typedi. You can access the playgrou ...

Modifying the version target of TypeScript code results in the TypeScript Compiler being unable to locate the module

After installing signalr via npm in Visual Studio 2019, I encountered an issue. When the target in my compiler options is set to ES6, I receive the error TS2307 (TS) Cannot find module '@microsoft/signalr.'. However, when I change the target to E ...

Running the NPM build command results in an error specifically related to an HTML file

I encountered an issue in my AngularJS application when running the command: npm run build -- -prod The error message I received was: ERROR in ng:///home/directoryling/appname-play.component.html (173,41): The left-hand side of an arithmetic operation ...

Updating from webpack v1 to v2 using webpack-cli results in a tsx error during migration

Encountering an error during the build process after migration, I'm unsure if it's related to the recognition of tsx files or something within them that is causing issues: Failed to compile. Error in ./src/index_app.tsx Module parse fail ...

TS - Custom API hook for making multiple API requests - incompatible type with 'IUseApiHook'

What is my objective? I aim to develop a versatile function capable of handling any type of API request for a frontend application. Essentially, I want to add some flair. Issue at hand? I find myself overwhelmed and in need of a fresh perspective to revi ...

Extracting data from a JSON object using Angular 2

I need advice on the most efficient way to handle JSON within my angular2 application. The JSON data I am working with includes: { "rightUpperLogoId": { "id": 100000, "value": "" }, "navbarBackgroundColorIdCss": { "id" ...

The index declaration file has not been uploaded to NPM

After creating a Typescript package and publishing it on NPM, I encountered an issue with the declaration files not being included in the published version. Despite setting declaration: true in the tsconfig.json, only the JavaScript files were being publis ...

How to Validate Ionic 2 Radio Button Selections with TypeScript

Imagine having a list like the one shown below: <ion-list radio-group [(ngModel)]="autoManufacturers"> <ion-list-header> Auto Manufacturers </ion-list-header> <ion-item> <ion-label>Cord</ion-label> &l ...

Angular auto suggest feature

I am working with a dropdown in Angular that contains JSON data. The data is stored in a List named options and I need to display the name field in the dropdown list. My current task involves implementing an autocomplete search feature for this dropdown. ...

Unable to locate module src/ in Node.js TypeScript

I'm encountering issues with non-relative imports in my node.js / typescript application. Here is my tsconfig: { "compilerOptions": { "target": "es6", "module": "commonjs", "lib": ["dom", "es6", "es2017", "esnext.asynciterable"], "s ...

Employ a type as a function in Typescript programming

Looking for a way to convert an ID into an object using a specific type. The type accepts personId as a string parameter and returns either a Person or undefined. export type FindPerson = (personId: string) => Person | undefined; I have multiple person ...

Converting API response into a class instance using `class-transformer` in TypeScript: A step-by-step guide

When working with TypeScript, I have a regular method called Request(method: HttpMethod, url: string, ...) that is used for calling APIs. Now, my goal is to convert the response from this API request into an instance of a class using class-transformer (or ...

The communication between Angular and Unity using SignalR for messaging is not functioning properly, as I am unable to

Trying to establish a connection between Angular and Unity has been challenging for me. I can't seem to get them to communicate with each other. My goal is to have Angular "announce" when someone enters a room, and have Unity "greet" the user enterin ...

What kind of null/undefined is being assumed?

system details: Visual Studio Code Version: 1.47.3 Typescript Version: 4.0.0-dev.20200727 tsconfig.js: "strict": true, code example: let x = null; // x is any type let y = x; // x is null type(why? x is any type on top), y is null type x = 1; / ...

Challenge faced: Angular array variable not refreshing

I am currently working on a map application where users can input coordinates (latitude and longitude). I want to add a marker to the map when the "Add Waypoint" button is clicked, but nothing happens. Strangely, entering the values manually into the .ts f ...