Impersonate Native DOM Elements with React Components and TypeScript for Full Reusability

Shawn Wang
InstructorShawn Wang

Share this video with your friends

Send Tweet
Published 3 years ago
Updated a year ago

Individually defining props doesn't scale especially if you are wrapping native DOM elements, for example for the purpose of building up a Design System. Fortunately, there are easy strategies to lend full TypeScript support to your custom React elements, without excessive typing.

Instructor: [00:03] Let's say I've been making my React and TypeScript app and I've been using a native dom element for a while. Then I decide to make a reusable component to add some extra features, for example, a label property.

[00:19] Here I've defined a label prop, and I've used it as my text. I decide to swap out my small-b button for my large-b custom button and specify my label inside a prop instead of in the native button.

[00:39] This refactoring works. Maybe this is the start of my new design system. However, the problem comes in when I start to want to use the other properties of a button.

[00:53] For example, if I wanted to pass in custom styles, and for example, I wanted to make styling to have a border of five-px-solid-green and I passed it in here, that would not work because style is not a declared prop of button.

[01:19] One way to resolve this is to add a style prop explicitly declared. I can declare inside my prop. I can add a style. It will be optional. I can say it takes React.css properties. Now I can apply the style to props. Style equals to props.style.

[01:44] The problem is that this approach doesn't scale. The button inherits properties and attributes from the general HTML interface, the HTML attributes, as well as the specific button element interface. All of those things can be looked up in index.d.ts inside of your node modules, inside of @types/reactindex.t.ts.

[02:13] You could conceivably refactor to spread your props, but that still leaves the task of laboriously defining every single prop that a button has on top of your synthetic button. What you really want to have is all of the base properties of the button element, which you can copy and paste.

[02:41] Then for the remaining props that you want to continue to add, you can just use an intersection type. That resolves both your custom properties, as well as the general other properties that are required as well.

[02:59] For example, on-click is defined neatly without needing to define it manually yourself.