Leveraging TypeScript to Create Better Polymorphic React Components | by Chisom Okoye | Jun, 2022

Write versatile elements

Reusable elements are one of many key ideas in React — the place you write a element as soon as and get to reuse them a number of instances.

Mainly your element would obtain some props, You then go forward to make use of these internally after which lastly render some React component which will get translated to the corresponding DOM component.

So what if my element can present me the pliability of controlling regardless of the container component/node may be? That is what gave beginning to the sample generally known as Polymorphism.

By definition, the phrase Polymorphic means present in a couple of kind.

On the planet of React elements, a polymorphic element is a element that may be rendered with a distinct container component.

With that stated although it’s potential that you simply’ve by no means heard of a polymorphic element earlier than. It’s a sample for code reusability similar to customized hooks, greater order element and so on.

Let’s say we’ve got a shareable <Field /> element and we wish to resolve what the precise component could be in 2 completely different circumstances,

  • We wish to render the Field element as an anchor component with href attribute
  • We wish the Field element to be a heading component of h1.

Now with the idea of polymorphism in React, we are able to make this potential by including an as props to the element to permit the caller to have the pliability of defining the HTML tag of their selection.

<Field as="a" href="https://www.linkedin.com/in/chisom-okoye-399112122/">
Dwelling web page

<Field as="h1">Principal heading</Field>

Constructing your first polymorphic element is kind of easy, here’s a primary implementation:

export const Field =(as, youngsters, ...others)=> 

One factor to notice right here is that we default the as props to be span in case the place the person is not passing the props, it ought to work with a span because the HTML component.

And secondly, we will not make use of the as props instantly as React will assume it’s the title of an HTML tag (<as>) which isn’t. So we have to first assign it to a capitalize variable after which render it.

Additionally, the ...others is essential as a result of we unfold it into <Part> as effectively. This enables us to go alongside extra attributes or props that we don’t find out about to the underlying component. An instance is a href attribute wanted for the <a> tag or the alt attribute used for an Picture <img>.

That’s all we have to construct a primary polymorphic element.

Nevertheless, the issue with this method is that there isn’t a manner or means to forestall the person from passing in unsupported props or passing in an invalid HTML component. i.e once we use this element as h1 the person is perhaps tempted to go alongside href attribute or the person would go in any worth for the as props which isn’t a sound HTML component.

Right here comes the advantage of Typescript in React.

To leverage typescript in making a bug free and higher expertise polymorphic element, it’s essential to first be sure that the react software has typescript. To create a react typescript challenge you need to use the command npx create-react-app project-name --template typescript or so as to add typescript to an present react software, npm or yarn may be use npm set up --save typescript @varieties/node @varieties/react @varieties/react-dom @varieties/jest. Then with the understanding of generic in typescript in we are able to tighten up the props being handed to the element.

Higher Implementation

import  ComponentPropsWithoutRef, ElementType, ReactNode  from "react";

kind BoxProps<T extends ElementType > =
as?: T;
youngsters: ReactNode;

export const Field =<T extends ElementType = "span">(
: BoxProps<T> & ComponentPropsWithoutRef<T>) =>
let Part = as

What we’re basically doing right here is that we create a kind for the Field element which is

kind BoxProps<T extends ElementType> = 
as?: T;
youngsters: ReactNode;


The place T extends ElementType is a generic kind, stating that T is a particular variable kind for the argument in our case the argument is as then the extends ElementType imply we’re constraining the generic to be a sound HTML Component, i.e as cannot be receiving values that is not an accurate HTML component.

It’s also good to notice that the ? operator connected to the as is to make it optionally available so typescript will not shout about this error when the element is not receiving the as props. Whereas the kids’s props must be a ReactNode kind.

Then on the level of making the Field element you’ll be able to see that our generic kind T was assigned to “span”, which means that the default component for as props could be span when the person is not passing any. Then we make the most of the BoxProps kind we created to be the kind for the argument we expect.

The following unusual syntax from our Field Part is & ComponentPropsWithoutRef<T>.

In case you are coming from Styled-components this syntax will not be unusual to you as a result of it’s truly the syntax format for styling pseudocode:

shade : blue;
shade: purple;

So in TypeScript we extract this format and introduce one thing generally known as intersection, which means that the kind BoxProps is an object kind containing as, youngsters and based mostly on the kind of as props we are going to return legitimate element props that correlate with the string attribute handed.

With that stated if we go-ahead to check out our <Field /> element wrongly e.g by passing a sound as props with the opposite incompatible props, you’re going to get an error.

<Field as="h1" href="https://www.linkedin.com/in/chisom-okoye-399112122/">
Principal heading

h1 is an ideal HTML component for the as props, however a h1 component shouldn’t have an href attribute. That is improper and throughout the runtime, typescript will assist catch this error as: Property 'href' doesn’t exist on kind …

That is nice as a result of we’ve got gotten a greater developer expertise and a fair higher sturdy resolution.

More Posts