Replace wildcard imports with specific named imports:
// ❌ Before
import * as React from "react";
// ✅ After
import { useState, useEffect, forwardRef } from "react";
Convert type aliases to interfaces and use ComponentPropsWithRef
:
// ❌ Before
type ButtonProps = React.HTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary";
};
// ✅ After
interface ButtonProps extends ComponentPropsWithRef<"button"> {
variant?: "primary" | "secondary";
}
// ❌ Before
type Props = BaseProps &
ExtraProps & {
custom?: boolean;
};
// ✅ After
interface Props extends BaseProps, ExtraProps {
custom?: boolean;
}
// ❌ Before
const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
return <button ref={ref} {...props} />;
});
Button.displayName = "Button";
// ✅ After
function Button(props: ButtonProps) {
return <button {...props} />;
}
// ❌ Before
export { Button, Input, Select, someConstant };
// ✅ After
export const someConstant = 1;
export function Button() {
/* ... */
}
export function Input() {
/* ... */
}
export function Select() {
/* ... */
}
Replace unsafe polymorphic components (Slot
pattern) with render props:
// ❌ Before - Unsafe Slot Pattern
function Button({ asChild, ...props }: { asChild?: boolean }) {
const Comp = asChild ? Slot : "button";
return <Comp {...props} />;
}
// ✅ After - Safe Render Props Pattern
import { RenderProp } from "~/shared/render-props";
interface ButtonProps {
render?: RenderProp; // intentionally not type RenderProp<XXX> for polymorphic usage
// other props...
}
function Button({
render = (props) => <button {...props} />,
...props
}: ButtonProps) {
return render(props);
}
- The
RenderProp
type from~/shared/render-props.ts
is intentionally not generic to support polymorphic usage - Default render function should always be provided for better DX
- Avoid using
React.cloneElement
as it will be deprecated in future React versions
- Use
ComponentPropsWithRef<T>
instead ofComponentProps<T>
when spreading all props - Import types directly from 'react' instead of using namespace imports
This refactoring guide ensures better type safety, modern React patterns, and future-proof components for React 19.