How to properly type the `mergeProps` with Typescript?

I'm using the mergeProps function to enter some default props for my component, but this is causing a Typescript error because some properties that are using string literals are being replaced with just type string.
interface ButtonBaseProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
color?: ColorNames;
}

function ButtonBase(props: ButtonBaseProps) {
const p = mergeProps({ variant: "filled", type: "button" }, props);

return (
<button
class={join(
"flex items-center rounded-full py-2 outline-none",
getButtonStyles(p.variant, p.color),
p.children ? "px-4" : "px-2"
)}
{...p}
/>
);
}
interface ButtonBaseProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
color?: ColorNames;
}

function ButtonBase(props: ButtonBaseProps) {
const p = mergeProps({ variant: "filled", type: "button" }, props);

return (
<button
class={join(
"flex items-center rounded-full py-2 outline-none",
getButtonStyles(p.variant, p.color),
p.children ? "px-4" : "px-2"
)}
{...p}
/>
);
}
<button is trowing an error because p.type is now typed as a string.
Type 'string' is not assignable to type '"button" | "submit" | "reset" | undefined'.
getButtonStyles is trowing an error because p.variant is now a string instead of ButtonVariant.
Argument of type 'string' is not assignable to parameter of type 'ButtonVariant'.
Is there a way where I can type this to solve this issue?
2 Replies
jesseb34r
jesseb34r2y ago
Idk how to answer your question but this thread was about mergeprops types https://discord.com/channels/722131463138705510/1049169598299250718
Ninguern
NinguernOP2y ago
Thanks @jesseb34r. I took a look at the answers and came to what I believe it's a good solution. I've updated my typescript to the ^4.9 version where I could use the satisfies operator and created a const for the default props. This seems to be the most organised solution I've found. Now it looks like this:
interface ButtonBaseProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
color?: ColorNames;
}

const defaultProps = {
variant: "filled",
color: "primary",
type: "button",
} satisfies ButtonBaseProps;

function ButtonBase(props: ButtonBaseProps) {
const p = mergeProps(defaultProps, props);

return (
<button
class={join(
"flex items-center rounded-full py-2 outline-none",
getButtonStyles(p.variant, p.color),
p.children ? "px-4" : "px-2"
)}
{...p}
/>
);
}
interface ButtonBaseProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
color?: ColorNames;
}

const defaultProps = {
variant: "filled",
color: "primary",
type: "button",
} satisfies ButtonBaseProps;

function ButtonBase(props: ButtonBaseProps) {
const p = mergeProps(defaultProps, props);

return (
<button
class={join(
"flex items-center rounded-full py-2 outline-none",
getButtonStyles(p.variant, p.color),
p.children ? "px-4" : "px-2"
)}
{...p}
/>
);
}
Want results from more Discord servers?
Add your server