Growing Polymorphic Elements in TypeScript

Growing Polymorphic Elements in TypeScript

[ad_1]

On this fast tip, excerpted from Unleashing the Energy of TypeScript, Steve displays you how you can use polymorphic parts in TypeScript.

In my article Extending the Homes of an HTML Component in TypeScript, I informed you that, over the path of creating out a big utility, I generally tend to finally end up making a couple of wrappers round parts. Field is a primitive wrapper across the elementary block parts in HTML (akin to <div>, <apart>, <phase>, <article>, <major>, <head>, and so forth). However simply as we don’t wish to lose the entire semantic that means we get from those tags, we additionally don’t want a couple of diversifications of Field which can be all mainly the similar. What we’d find irresistible to do is find Field but in addition have the ability to specify what it must be below the hood. A polymorphic element is a unmarried adaptable element that may constitute other semantic HTML parts, with TypeScript mechanically adjusting to those adjustments.

Right here’s a very simplified tackle a Field part impressed by way of Styled Elements.

And right here’s an instance of a Field element from Paste, Twilio’s design gadget:

<Field as="article" backgroundColor="colorBackgroundBody" padding="space60">
  Mother or father field at the hill aspect
  <Field
    backgroundColor="colorBackgroundSuccessWeakest"
    show="inline-block"
    padding="space40"
  >
    nested field 1 produced from ticky cheesy
  </Field>
</Field>

Right here’s a easy implementation that doesn’t have any move thru any of the props, like we did with Button and LabelledInputProps above:

import { PropsWithChildren } from 'react';

sort BoxProps = PropsWithChildren< 'article' >;

const Field = ({ as, kids }: BoxProps) => {
  const TagName = as || 'div';
  go back <TagName>{kids}</TagName>;
};

export default Field;

We refine as to TagName, which is a sound element title in JSX. That works as a long way a React is anxious, however we additionally wish to get TypeScript to conform accordingly to the part we’re defining within the as prop:

import { ComponentProps } from 'react';

sort BoxProps = ComponentProps<'div'> &  'article' ;

const Field = ({ as, kids }: BoxProps) => {
  const TagName = as || 'div';
  go back <TagName>{kids}</TagName>;
};

export default Field;

I truthfully don’t even know if parts like <phase> have any houses {that a} <div> doesn’t. Whilst I’m certain I may just glance it up, none folks be ok with this implementation.

However what’s that 'div' being handed in there and the way does it paintings? If we have a look at the kind definition for ComponentPropsWithRef, we see the next:

sort ComponentPropsWithRef<T extends ElementType> = T extends new (
  props: infer P,
) => Part<any, any>
  ? PropsWithoutRef<P> & RefAttributes<InstanceType<T>>
  : PropsWithRef<ComponentProps<T>>;

We will forget about all of the ones ternaries. We’re concerned with ElementType at this time:

sort BoxProps = ComponentPropsWithRef<'div'> & {
  as: ElementType;
};

A autocompleted list of all of the element types

K, that’s fascinating, however what if we needed the kind argument we give to ComponentProps to be the similar as … as?

We may just check out one thing like this:

import { ComponentProps, ElementType } from 'react';

sort BoxProps<E extends ElementType> = Disregard<ComponentProps<E>, 'as'> & {
  as?: E;
};

const Field = <E extends ElementType="div">({ as, ...props }: BoxProps<E>) => {
  const TagName = as || 'div';
  go back <TagName {...props} />;
};

export default Field;

Now, a Field element will adapt to no matter part sort we move in with the as prop.

A Box with the props of a button

We will now use our Field element anywhere we may another way use a <div>:

<Field as="phase" className="flex place-content-between w-full">
  <Button className="button" onClick={decrement}>
    Decrement
  </Button>
  <Button onClick={reset}>Reset</Button>
  <Button onClick={increment}>Increment</Button>
</Field>

You’ll see the general end result on the polymorphic department of the GitHub repo for this educational.

This newsletter is excerpted from Unleashing the Energy of TypeScript, to be had on SitePoint Top class and from guide shops.



[ad_2]

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back To Top
0
Would love your thoughts, please comment.x
()
x