The error message "Type 'null' cannot be assigned to type 'Element | DocumentFragment'" occurs when using Nextjs/React createPortal

I am completely new to typescript.

Currently, I'm working on a project that has a lot of pre-configured react components in JavaScript files (.js). My task now is to convert everything to TypeScript (.tsx) without triggering any ESLint errors. Unfortunately, I can't use the non-null assertion (!) due to my ESLint configuration.

My current challenge is converting a portal component (createPortal) to TypeScript, and I'm encountering various errors based on the types I define.

This is the code snippet:

import { useRef, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import React from "react";
import { useCallback } from "react";

type ClientOnlyPortalProps = {
  children: React.ReactNode;
  // Is there a type for CSS id?
  selector: string;
};

export default React.memo(function ClientOnlyPortal({
  children,
  selector,
}: ClientOnlyPortalProps) {
  const ref = useRef<Element | DocumentFragment | null>(null);
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                          //1. not sure if this is correct^
  const [mounted, setMounted] = useState(false);

  if (ref == null) {
  }

  useEffect(
    useCallback(() => {
      ref.current = document.querySelector(selector);
      setMounted(true); 
       ^^^^
         //2. ref.current has a ts error if I remove null from #1
      console.log("ClientOnlyPortal useEffect fired");
    }, [selector])
  );

  return mounted ? createPortal(children, ref.current) : null;
                                          ^^^^^^^^^^^
                                     //3. This error is always here
});

  1. If I remove null from here, then I get an error @ #2.

This is potential error @ #2:

Cannot assign to 'current' because it is a read-only property.ts(2540)

  1. This error is always here:
Argument of type 'Element | DocumentFragment | null' is not assignable to parameter of type 'Element | DocumentFragment'.
  Type 'null' is not assignable to type 'Element | DocumentFragment'.ts(2345)

Any assistance would be highly appreciated!

Hoping that by converting all my JavaScript components into TypeScript, I will significantly improve my skills in TypeScript. In need of a TypeScript tutor :/

.................................................................

Answer №1

I managed to resolve my issues by taking the following steps. Any helpful feedback?

 import { useRef, useEffect, useState } from "react";
    import { createPortal } from "react-dom";
    import React from "react";
    import { useCallback } from "react";
    
    type ClientOnlyPortalProps = {
      children: React.ReactNode;
      // Is there a type for CSS id?
      selector: string;
    };
    
    export default React.memo(function ClientOnlyPortal({
      children,
      selector,
    }: ClientOnlyPortalProps) {
      const ref = useRef<Element | DocumentFragment | null>(null);
                               ^^^^^^^^^^^^^^^^^^^^^^^^
                                    //included this line
      const [mounted, setMounted] = useState(false);
    
      //eslint-disable-next-line
      useEffect(
        useCallback(() => {
          ref.current = document.querySelector(selector);
          setMounted(true);
          console.log("ClientOnlyPortal useEffect fired");
        }, [selector])
      );
    
      if (ref.current == null) {
        return null;
      }
        ^^^^^^^^^^ 
           //Added this line

      return mounted ? createPortal(children, ref.current) : null;
    });

Note that the 'eslint-disable-next-line' is included due to an issue indicating:

React Hook useEffect received a function whose dependencies are unknown. Pass an inline function instead.

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

Recursive types in TypeScript allow for the definition of types that

Is there a way to implement the function below without utilizing any? Playground type MyType = { name: string, age: number, score: { prime: number, }, prize: { first: { discount: number } } } export const trim = ( myObj: ...

Issue with accessing options in onChange event with Material-UI useAutocomplete

I'm facing an issue where I can't seem to access the option.slug from the object provided by the API. My goal is to utilize this slug in order to change the route of my application using the onChange prop within the useAutocomplete() definition. ...

What is the method for determining the type of a TypeScript class member that is associated with a commonly used symbol such as Symbol.toStringTag?

Does anyone know the correct TS syntax for extracting the type of a class method indexed with a well-known Symbol? Here are two incorrect methods: type T = String[Symbol.toStringTag]; // 'Symbol' only refers to a type, but is being used as a name ...

Error encountered in Vue code, lacks default export on Editor Terminal

I'm not experiencing any issues in the browser, I am getting the desired output. However, why does this keep showing up in the editor terminal? Any assistance would be greatly appreciated. Error - No Default Export: The module "/vue3/src/components/ ...

Tips for sending a parameter to an onClick handler function in a component generated using array.map()

I've been developing a web application that allows users to store collections. There is a dashboard page where all the user's collections are displayed in a table format, with each row representing a collection and columns showing the collection ...

What could be the reason for the 'tsc' command not functioning in the Git Bash terminal but working perfectly in the command prompt?

I recently installed TypeScript globally on my machine, but I am facing an issue while trying to use it in the git bash terminal. Whenever I run tsc -v, I encounter the following error: C:\Users\itupe\AppData\Roaming\npm/node: l ...

The setting of the custom user agent in the Chrome Extension Manifest Version 3 is not functioning correctly

We currently have an extension that consists of only two files: manifest.json and background.js Despite the browser (Chrome version 112) not reporting any errors, we are facing an issue where the user agent is not being set to 'my-custom-user-agent&a ...

Oops! An issue occurred on the server: ReferenceError - 'window' is not defined. This error occurred during

I'm looking to integrate a Microsoft Login Button into a Next Js application using Material UI. However, after adding the necessary package from NPM and refreshing the page, I encountered the error mentioned above. When I tried setting ClientId="a973 ...

Tips for triggering functions when a user closes the browser or tab in Angular 9

I've exhausted all my research efforts in trying to find a solution that actually works. The problem I am facing is getting two methods from two different services to run when the browser or tab is closed. I attempted using the fetch API, which worke ...

Enumerate the names of the private properties within the class

I am working on a problem where I need to use some of the class properties as values in a map within the class. In the example below, I have used an array instead of a map because when a property is marked private, it is not included in the keyof list. How ...

Is it feasible to evaluate a Typescript method parameter decorator at request time in a nodejs+nestjs environment rather than just at build time?

Looking to simplify my handling of mongodb calls with and without transactions in a single service method by writing a decorator. This would help eliminate the repetition of code and make things more efficient. Key points for usage: • Service class has ...

Encountering an issue with Next.js 14.0.3 and Next Auth 4.24.4 where the session callback is not providing the token upon refresh. Workaround is to switch tabs

Encountering an issue where the app works fine in development mode but encounters problems in production mode. When running in production mode either locally or on Vercel, the session token is missing upon page refresh. However, switching browser tabs or o ...

How can I retrieve the value of a promise in Promise.map?

I am currently working on a project that involves saving data to a database using Mongoose. One specific field in the database is the 'thumbnail' field, which needs to be filled with a base64 converted file after the file is uploaded to the serve ...

Issue: The module '@nx/nx-linux-x64-gnu' is not found and cannot be located

I'm encountering issues when trying to run the build of my Angular project with NX in GitHub Actions CI. The process fails and displays errors like: npm ERR! code 1 npm ERR! path /runner/_work/myapp/node_modules/nx npm ERR! command failed npm ERR! c ...

Internationalization in Angular (i18n) and the powerful *ngFor directive

Within my Angular application, I have a basic component that takes a list of strings and generates a radio group based on these strings: @Component({ selector: 'radio-group', templateUrl: `<div *ngFor="let item of items"> ...

What could be causing FormArrayName to consistently display as undefined in my HTML code, even when the safe-navigation operator is employed

Currently, I'm referring to the Angular Material example found at https://angular.io/api/forms/FormArrayName Upon initializing the packageForm formGroup in ngOnInit() and logging it in the console during ngAfterViewInit(), I can see that the translat ...

Issue with Navbar collapse button not displaying items on Bootstrap 4.5.0 in combination with Next.js version 9.4.4

I'm currently working on a nextjs demo project where I'm incorporating bootstrap for styling purposes. The initial setup was straightforward as I installed bootstrap using npm and included it in my app.js. import 'bootstrap/dist/css/bootstra ...

What is the best way to navigate to a different URL using useRouter in Next.js?

I have a simple search bar component in my Next.js application that I want to include in the main navbar and also use on a dedicated search page. The goal is to redirect the user to "/search?q=INPUTVALUE" upon submission. However, instead of going to the s ...

Mixing a static class factory method with an instance method: a guide

After introducing an instance method addField in the code snippet below, I encountered an issue with the Typescript compiler flagging errors related to the static factory methods withError and withSuccess: The error message states: 'Property ' ...

Angular 8: Implementing Form Validation with a Boolean Flag

Within my HTML code, I have a function (change)="limitUser($event)". In Typescript, I utilize a for loop to iterate through each element and determine if the value is less than 10. If it exceeds 10, the inValid = true condition is set. All form fields in m ...