I’m creating a component that can be a Button or Anchor tag. But I’m having trouble making a conditional typing for the ref. How can I get the ref to be accepted?
type ConditionalProps =
| ({
as: "button";
} & React.ButtonHTMLAttributes<HTMLButtonElement>)
| ({
as: "a";
} & React.AnchorHTMLAttributes<HTMLAnchorElement>);
const Trigger = forwardRef<
HTMLAnchorElement | HTMLButtonElement, // <- this is an issue
ConditionalProps
>(function Trigger({ as, ...props }, ref) {
return createElement(as, {
...props,
ref, // <- error
});
});
The error states:
Type 'ForwardedRef<HTMLAnchorElement | HTMLButtonElement>' is not
assignable to type 'Ref<HTMLAnchorElement> | undefined'.
2
Answers
You could have two
return
statements depending on theas
property you get, and use TypeScript assertions for the given type.Trying your code I didnt get type errors, union seemed fine on https://codesandbox.io/s/react-typescript-forked-elwo35?file=/src/App.tsx
But whenever for these kind of situations I think generics work well, its just one type so fairly simple.
So usually can set up some types like this, bit verbose here for clarity.
Then you can make your component generic, in this example I’m using a custom ref prop instead of forward, the logic is the same it’s just annoying to do with forwardref you have to wrap the whole thing in another component with custom ref anyway and then forward that one with generic..
Here’s a full example https://codesandbox.io/s/react-typescript-forked-k2flhc?file=/src/App.tsx