Array of React components with covariant types

I have a custom class that extends a base class and combines the properties of both. Here is an example:

interface BaseFooProps {
  name: string;
}
type BaseFoo<T extends BaseFooProps = BaseFooProps> = React.FC<T & BaseFooProps>;
const BaseFooComponent: React.FC<BaseFooProps> = ({ name }) => <>{name}</>;

Now, let's look at the derived class:

interface AProps extends BaseFooProps {
  height: number;
}
const A: React.FC<AProps> = ...

Next, I want to create another component that receives an array of these BaseFoo components. This ensures that each item in the array has at least the base properties:

interface OtherBarProps {
  items: BaseFoo[]
};

const OtherBar: React.FC<OtherBarProps> = ...

const items = [
  <A name=... height=... key=... />,
];
<OtherBar items={components} />

However, there is an error on the last line, stating that

Type 'Element[]' is not assignable to type 'BaseFoo<BaseFooProps>[]'
.

I have tried different approaches like casting items with as ..., modifying the left-hand side, and adding {} to the

React.FC<T & BaseFooProps>
definition, but none of them resolved the issue.

Why are the elements in the array being cast as so generic to Element instead of BaseFoo? How can I make the type system accept them correctly?

Answer №1

It appears that there may be some confusion between the Element and Component types. An instance of a component (element) like <A/> is not the same as the actual component function itself, such as const A = () => {...}. To pass instances correctly, you should use React.ReactElement.

interface OtherBarProps {
  items: React.ReactElement<BaseFooProps>[]
  // You can also use a different type
  // items: React.ReactElement<React.ComponentProps<BaseFoo>>[]
};

const items = [
  <A name="Joe" height={42} />,
];

<OtherBar items={items} />

Unfortunately, it seems that to enforce specific element types, you will need to set explicit types for each element. This is because all React components currently return JSX.Element, even if you specify a return type like

React.ReactElement<PropType>
.

You could approach it like this:

const newA: React.ReactElement<AProps> = <A name="Joe" height={42} />;
const button: React.ReactElement<{}> = <button/>

const items = [
  newA,
  button
];

// Property 'name' is missing in type '{}' but required in type 'BaseFooProps'.
<OtherBar items={items} />

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

Attempting to retrieve a URL using Angular/Typescript is generating an Unknown Error instead of the expected successful response

I'm trying to make a simple HTTP function call through TypeScript (Angular) to an API hosted as a function in Azure. When I call the URL through Postman or directly in the browser, everything works perfectly. However, when I try to call the URL usin ...

Step-by-step guide for adding an object to a Material UI select component

I am in the process of incorporating a Select component with reactjs material ui and typescript. Yet, I encounter this typing error: Property 'id' does not exist on type 'string'. Property 'name' does not exist on type ' ...

The Google Sign-in feature is unable to access the property 'load' due to being undefined

I'm currently working on implementing a Google Sign-in feature in an Angular application, but I'm encountering the following error: Cannot read property 'load' of undefined This was actually working perfectly just an hour ago, but n ...

The use of `super` in Typescript is not returning the expected value

Trying to retrieve the name from the extended class is causing an error: Property 'name' does not exist on type 'Employee'. class Person { #name:string; getName(){ return this.#name; } constructor(name:string){ ...

Managing Keyboard Input in React using TypeScript

Hey there! I'm currently working on a method that should automatically insert a specific string into a textbox when a particular key is pressed. The key in question is a non-printable character that may not be visible in most font styles, but can sti ...

Retrieve properly formatted text from the editor.document using the VSCode API

I have been working on creating a personalized VSCode extension that can export the current selected file contents as a PDF. Although PrintCode exists, it does not fit my specific needs. The snippet of code I am currently using is: const editor = vscode.w ...

"Disabling a FormControl within a FormArray in Angular 4: A Step-by-

I've come up with a code snippet below that I thought would disable the FormControl in a FormArray. some.component.html <form [formGroup]="testForm"> <div *ngFor="let num of countArr"> <input type="text" formNameArray="arr ...

Ways to implement es6 in TypeScript alongside react, webpack, and babel

Being new to front-end development, I have found that following a simple tutorial can quickly help me start tackling problems in this field. One issue I've encountered is with ES5, which lacks some of the tools that are important to me, like key-value ...

Tips for incorporating momentjs into TypeScript within AngularJS 1.5

I am looking to integrate the momentJs library into my TypeScript code for Date object operations. However, I need some guidance on how to inject TypeScript in AngularJS, as it differs slightly from JavaScript. angular.module("app") .config(functio ...

Getting the Class name in Typescript

How can you retrieve the class name from within a Class in typescript? For instance, consider this code snippet: export class SomeRandomName extends AbstractSomething<SomeType> implements OnDestroy { className = 'SomeRandomName'; Is th ...

encountering the issue of not being able to assign a parameter of type 'string | undefined' to a parameter of type

Seeking help with the following issue: "Argument of type 'string | undefined' is not assignable to parameter of type" I am unsure how to resolve this error. Here is the section of code where it occurs: export interface IDropDown { l ...

Achieving a clean/reset for a fetch using SSR in Next 13

Is there a way to update the user variable in the validateToken fetch if a user signs out later on, such as within a nested component like Navigation? What is the best approach to handle clearing or setting the user variable? Snippet from Layout.tsx: impo ...

Creating a regular expression for validating phone numbers with a designated country code

Trying to create a regular expression for a specific country code and phone number format. const regexCountryCode = new RegExp('^\\+(48)[0-9]{9}$'); console.log( regexCountryCode.test(String(+48124223232)) ); My goal is to va ...

What is the best way to iterate over an Angular HTTP Response?

As a newcomer to Angular, I am working on mastering the process of uploading files and calling an API for validation. The API responds with a list of JSON validation errors based on specific file values. I am currently struggling to iterate through these ...

Exploring how Jasmine tests the checkbox change handler function in the latest version of Angular (12)

I'm attempting to create a basic test function for a checkbox change event, but I'm encountering some issues running it. The error message states "Spec has no expectations," and the handler function is not included in code coverage. Template: &l ...

The ordering of my styles and Material-UI styles is causing conflicts and overrides

Greetings fellow developers! I'm currently facing an issue with my custom styles created using makeStyles(...). The problem arises when I import my styles constant from another module, and the order of the style block is causing my styles to be overr ...

Creating a modal dialog using a function in a TypeScript file

Hey there, fellow developers! I have a question that might seem simple. So, in my HTML code I've got a Modal Dialog that pops up using ng2 Bootstrap. It's working fine, but... I want to replace this line of code "<button class="btn btn-prim ...

I'm facing some difficulties in sourcing my header into a component and encountering errors. Can anyone advise me on how to properly outsource my header?

Looking to streamline my headers in my Ionic 4 project by creating a separate reusable component for them. Here's how I set up my dashboard page with the header component: <ion-header> <app-header title="Dashboard"></app-he ...

Unreachable variable in Vue 2.0

I am new to Vue and facing an issue with accessibility. I have two files. The first file is App.vue where <router-view> is defined: <script> export default { name: 'app', data(){ return{ info: false, } }, befo ...

No response was forthcoming

I have been trying to send a post request to my login endpoint, but I am not receiving any response. Despite thoroughly checking my code, I am unable to figure out why there is no response being sent back. My backend is built using Express in TypeScript. B ...