tezvyn:

Design a type-safe polymorphic component that renders as different HTML elements

AI-drafted, machine-checkedSource: blog.logrocket.comadvanced
Design a type-safe polymorphic component that renders as different HTML elements

Tests TypeScript generics and prop forwarding in design systems. Answer: generic as constrained to keyof JSX.IntrinsicElements, merged with ComponentPropsWithoutRef<C>, omit clashes, forward ref with ElementRef.

WHAT THIS TESTS: This question probes whether you can bridge React runtime behavior with compile-time TypeScript safety at the design-system layer. It specifically checks your fluency with generics, constraint syntax, mapped types like JSX.IntrinsicElements, and ref forwarding across unknown element types. Interviewers want to see that you understand the difference between a component that merely accepts an as prop and one that actually validates attributes against the chosen element.

A GOOD ANSWER COVERS: First, declare a generic as prop constrained to React.ElementType or keyof JSX.IntrinsicElements so only valid HTML tags or components are accepted. Second, compute the element-specific props by using React.ComponentPropsWithoutRef<C> and intersecting them with your own props, while strictly omitting any keys that clash with your custom API such as color or size. Third, handle ref forwarding correctly by typing the ref as React.ElementRef<C> rather than a fixed HTML element type. Fourth, provide a default element such as span so the generic falls back gracefully when as is omitted. Fifth, optionally mention extracting a reusable PolymorphicProps<C, Props> utility so the pattern scales across Button, Link, and Typography primitives.

COMMON WRONG ANSWERS: A naive implementation types as as a plain string which lets users pass href to a p tag without a type error. Another red flag is using any for the ref or spreading props without generic constraints, which erases autocompletion and disables IDE IntelliSense. Some candidates suggest runtime prop filtering instead of compile-time type omission, showing they confuse validation with type safety. Finally, forgetting to omit your own props from the generic component props causes unresolvable type intersections when color exists both in your theme API and in standard HTML attributes.

LIKELY FOLLOW-UPS: The interviewer may ask how you would extend this to accept custom React components and not just HTML tags, which requires checking that the passed component satisfies the expected props interface. They might also ask how you prevent certain elements from being used, such as blocking div inside a Typography component, which can be done with a more restrictive generic constraint. Another common follow-up is how you handle displayName and defaultProps in a generic forwardRef component, or how tree-shaking and bundle size are affected by exporting many polymorphic primitives.

ONE CONCRETE EXAMPLE: Imagine a Typography component. When as is h1, TypeScript should allow id and className but reject disabled. When as is a custom Link component, it should surface Link-specific props such as to or replace while still restricting invalid HTML attributes. A senior candidate would define a type where C extends React.ElementType, then use Omit on React.ComponentPropsWithoutRef<C> to strip keys that overlap with the component own props, and intersect the result with those own props. They then wrap the implementation in React.forwardRef and type the ref as React.ElementRef<C>. This gives consumers full autocomplete for whichever element they choose while keeping the design system API strictly typed.

Source: LogRocket Blog

Read the original → blog.logrocket.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.