DEV Community 👩‍💻👨‍💻

Discussion on: Default Props in React/TypeScript

Collapse
chico1992 profile image
chico1992 • Edited on

Hi Adam the closest I came to a solution that could satisfy your need is following and everything is nicely typecheck

interface Props {
    requiredString: string;
    requiredNumber: number;
    optionalBoolean?: boolean;
    optionalString?: string;
    optionalNumber?: number;
}

export const MyTSComponent: React.FC<Props> = ({
    optionalString = "default",
    optionalBoolean = true,
    optionalNumber = 42,
    ...props
}) => {
    console.log(props);
    optionalString.split("");
    return (
        <>
            Here is MyComponent:
            <br />
            {props.children}
        </>
    );
};
Enter fullscreen mode Exit fullscreen mode

with this solution you could put the destructured props inside an args object inside your component

export const MyTSComponent: React.FC<Props> = ({
    optionalString = "default",
    optionalBoolean = true,
    optionalNumber = 42,
    ...props
}) => {
    const args = { optionalString , optionalBoolean , optionalNumber};
    console.log(props);
    args.optionalString.split("");
    return (
        <>
            Here is MyComponent:
            <br />
            {props.children}
        </>
    );
};
Enter fullscreen mode Exit fullscreen mode

And typescript has a Required type that does the same as your AllPropsRequired type

hope this helps

Collapse
bytebodger profile image
Adam Nathaniel Davis Author

Another "challenge" with the approach you've outlined here is that the requiredString and requiredNumber values only exist under the props object - but optionalString, optionalBoolean, and optionalNumber exist as standalone variables. As you've pointed out, you can get them back into one object, but you'd have to manually add requiredString and requiredNumber to that object as well.

That's not insurmountable, but I gotta play with it for a bit to see if there's a slicker way of handling that...

Collapse
chico1992 profile image
chico1992

You could try something around these lines

export const MyTSComponent: React.FC<Props> = ({
    optionalString = "default",
    optionalBoolean = true,
    optionalNumber = 42,
    ...args
}) => {
    const props = { optionalString , optionalBoolean , optionalNumber, ...args};
    console.log(props);
    props.optionalString.split("");
    return (
        <>
            Here is MyComponent:
            <br />
            {props.children}
        </>
    );
};

whit this you would get a fully typed props object that you could use as you used to

Thread Thread
bytebodger profile image
Adam Nathaniel Davis Author

I've actually built a helper function now that takes the existing props and a simple object that defines any default values and then returns it mapped to the Props type. I'll probably outline that in a near-future post.

Thanks for taking the time to point me along!

Collapse
bytebodger profile image
Adam Nathaniel Davis Author

First, thank you for showing me the Required type! I had no idea that existed. Makes a lot more sense than doing it manually with my own custom partial.

Second, I do like your approach. The only thing I find lacking in it, is the need to manually chunk those values into an args object (assuming you want them in a single object - like I do). But that's not really a huge objection, is it? Hmm...

From looking at your example, one of the problems with my prior approaches was probably that I wasn't consistently leveraging React.FC<>. From many of the examples I've been looking at online, it's not at all clear that this should be used whenever creating a functional React component - but I'm starting to think that's the case.

Very cool - thanks!!

Collapse
chico1992 profile image
chico1992

Your welcome

The nice thing about the React.FC is that it defines the return type of your function and it add children?: React.ReactNode to your props so no need to handle that prop yourself

Thread Thread
bytebodger profile image
Adam Nathaniel Davis Author

OIC. I think I had kinda stumbled into a different way to handle that. Cuz in my (final) example, my interface is defined as:

interface Props extends PropsWithChildren<any> {...}
Enter fullscreen mode Exit fullscreen mode

But I think I like the React.FC way better.