Potentially null object is present in a callback

The code I have is as follows:

             let ctx = ref.current.getContext("2d");
             if(ctx){
                ctx.lineWidth=1; // this line executes without errors
                ctx.strokeStyle=props.barStroke??"darkgray";// this line executes without errors
                ctx.fillStyle=props.barFill??"blue"; // this line executes without errors
                props.data.map((v,i)=>{
                    ctx.fillRect(i*10,0,10,props.height); // here it complains that ctx may be null!!
                    ctx.strokeRect(1*10,0,10,props.height);
                })

             }

While I have checked the value of ctx and found that ctx.lineWidth works fine, I encounter an error inside the callback indicating that the object could potentially be null. Interestingly, using ctx?.method allows the code to work regardless. How is it possible for ctx, confirmed as not null outside the callback, to become null inside it? Here is a link demonstrating the issue.

Answer №1

In reference to this issue:

The current behavior is by design. The type checker understands that `ctx` is not null when the callback function is created, but it cannot guarantee that `ctx` will still be non-null when the callback is actually executed (especially if `bar` is a mutable property that could change before or between calls).

A recommended approach to address this is to make a copy of `ctx` and use that as a constant local variable within the callback function.

Answer №2

Give this a shot:

      let canvasContext = ref.current.getContext("2d");
         if(canvasContext) {
            canvasContext.lineWidth=1; // all good here!
            canvasContext.strokeStyle=props.barStroke??"darkgray";// all good here!
            canvasContext.fillStyle=props.barFill??"blue"; // all good here!
            props.data.map((val,index)=>{
                canvasContext.fillRect(index*10,0,10, val.height); //no error for ctx being possibly null here!!
                canvasContext.strokeRect(1*10,0,10, val.height);
            })

         }

Seems like props is not causing an issue with the reference to ctx. It's because ctx is already defined as a local variable.

Answer №3

To gain insights into the reason behind this issue, please refer to Matthieu Riegler's explanation. An alternative approach is to implement a `for` loop instead of using a callback, as TypeScript may not accurately detect when the callback is invoked within the `.map` function, hence causing the problem:

let ctx = document.querySelector<HTMLCanvasElement>('foo')!.getContext("2d");
if (ctx) {
    const props = {
        data: ['x', 'y'],
        height: 10
    }
    for (const [i, v] of props.data.entries()) {
        ctx.fillRect(i * 10, 0, 10, props.height);
        ctx.strokeRect(1 * 10, 0, 10, props.height);
    }
}

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

How to extract multiple literals from a string using Typescript

type Extracted<T> = T extends `${string}${'*('}${infer A}${')+'}${string}${'*('}${infer A}${')+'}${string}` ? A : never type Result1 = Extracted<'g*(a12)+gggggg*(h23)+'> // 'a12' | &a ...

Generating a custom type in Typescript based on specific array keys

Imagine I have a structure like this: export interface MyObject { id: number title: string } and then I create an array as shown below: const myArray: MyObject[] = [ { id: 2358, title: 'Item 1' }, { id: 85373, title: &a ...

What is the best way to insert information into my SQLite database?

Hey there! I'm new to programming and recently started working on an IONIC App. However, I've hit a roadblock. My goal is to create a phone book feature where users can get random JSON contacts and save them to their sqlite database. Here's ...

Challenges when building a production version of an Expo app with Typescript

Attempting to perform a local production build, I ran expo start --no-dev --minify. Only the initial template file displays, stating "Open up App.tsx to start working on your app," and none of my work is visible... Has anyone else encountered this issue a ...

Failure to trigger the callback for mongoose.connection.once('open') event

Currently, I am in the process of setting up a custom Node server using Next.js. Although I'm utilizing Next.js this time around, it should not affect the outcome. In my previous applications, I always relied on mongoose.connection.once('open&ap ...

Loop through object properties with *ngFor

Seeking suggestions on how to iterate over object keys in HTML using *ngFor within Angular 12. The provided data structure is as follows: { "data": [ { "student1": { "name": "Jhon", &quo ...

Retrieve data from a URL using Angular 6's HTTP POST method

UPDATE: Replaced res.json(data) with res.send(data) I am currently working on a web application using Angular 6 and NodeJS. My goal is to download a file through an HTTP POST request. The process involves sending a request to the server by calling a func ...

Implementing dynamic data updates for the yAxis in a chart using Highcharts and Angular 2/4

I am currently working with a spline chart: this.chart = { chart: { type: 'spline', zoomType: 'x', animation: true, marginRight: 10, renderTo ...

Creating a digital collection using Vue, Typescript, and Webpack

A short while back, I made the decision to transform my Vue project into a library in order to make it easier to reuse the components across different projects. Following some guidelines, I successfully converted the project into a library. However, when ...

The parameter type ‘DocumentData’ cannot be assigned to type ‘never’ in this argument

I've been struggling to find a solution to my issue: Ts gives me an error: Argument of type 'DocumentData' is not assignable to parameter of type 'never' I attempted the solution I found on this page: Argument of type 'Docume ...

Version 4.0 of d3 introduces an import statement that provides a __moduleExports wrapper

Having difficulty with an import statement in my D3 4.0 and Ionic2/Angular2 project. I believe the import statement is correct, as everything compiles successfully. import * as d3Request from 'd3-request'; export class HomePage { construc ...

What is the best way to restrict the maximum number of items stored in local storage?

I'm creating a GitHub search app using the GitHub API in Angular. I want to restrict the number of items that can be stored in local storage. If the number of stored elements exceeds 5, the "Add to Favorite" button should either stop working or disapp ...

What could be causing my "Swiper" component to malfunction in a TypeScript React project?

In my React project, I decided to incorporate the Swiper library. With multiple movie elements that I want to swipe through, I began by importing it as follows: import Swiper from 'react-id-swiper'; Utilizing it in my code like this: <div cla ...

The function, stored as state within a context provider, is experiencing only one update

I am facing an issue with my Next.js and Typescript setup, but I believe the problem is more general and related to React. Despite extensive research on Stack Overflow, I have not come across a similar problem. To provide some context: I have a <Grid&g ...

Creating a consistent template for typing TypeScript generics

Is it possible to modify a generic function so that it can accept an unlimited number of arguments and concatenate them with .'s? This function should be able to handle nested objects with any number of keys. The current code snippet works when manua ...

What is the best way to connect input values with ngFor and ngModel?

I am facing an issue with binding input values to a component in Angular. I have used ngFor on multiple inputs, but the input fields are not showing up, so I am unable to push the data to subQuestionsAnswertext. Here is the code snippet from app.component ...

The Subscribe function in Angular's Auth Guard allows for dynamic authorization

Is there a way to check if a user has access by making an API call within an authentication guard in Angular? I'm not sure how to handle the asynchronous nature of the call and return a value based on its result. The goal is to retrieve the user ID, ...

What is the maximum allowable size for scripts with the type text/json?

I have been attempting to load a JSON string within a script tag with the type text/json, which will be extracted in JavaScript using the script tag Id and converted into a JavaScript Object. In certain scenarios, when dealing with very large data sizes, ...

Is there a way to ensure a consistent return value when using exhaustive switch-case statements?

I'm facing an issue with the following code snippet: function (flavors: IceCreamFlavor): 'like'|'dislike' { switch (flavors) { case IceCreamFlavor.vanilla: return 'dislike'; case IceCreamFl ...

Make sure the subset interface is selected from the interface / Choose PickDeep<>?

I am searching for a solution using the following interface: interface Person { age: number, name: string, hometown?: { city: string, zip: number } } type SubPerson = EnsureSubInterface<Person, { name: string }> an example that w ...