3

What is the best practice for having 2 optional props in a component required together with react/typescript.

export interface MyComponentProps {
  firstName?: string;
  lastName?: string;
}
const myComponent: React.FC<MyComponentProps> = (props) => { 
       return <div ...>
     }

my thoughts for requiring both being

export interface Name {
    firstName: string;
    lastName: string;
}
export interface MyComponentProps {
     name?: Name
}

Would this be the best way, or is there another solution out there?

Thomas
  • 31
  • 2
  • What is the problem with the first approach? – Vishnu Sajeev Jan 13 '22 at 02:57
  • I think OP is saying that they should either both be present or both be missing – Jared Smith Jan 13 '22 at 03:01
  • Correct, both present or both missing – Thomas Jan 13 '22 at 03:11
  • 1
    I've tried to make a generic type that does what you want. If @ghybs answer doesn't work, you can also try this one: https://www.typescriptlang.org/play?#code/LAKALgngDgpgBAOQIYFt4F44G9RzgMwEsAnAZzGTQC45zjCA7AcwG5c4AbJcymGuxq1ABfUKEiw4AIQD2YABYB5YghkMYAHgAqAPjiYASjACOAVxIwAJtr0AfOAAUkxMISQcNRgMYzi1gNYwEDL4cFoANHCmDJYwROqWOjpsIOLQ8ACyEADCMihQajAMYA7EMlCk+tJySiqFGrzJYiA+DORwahwQAGIkPKh8cFm5+YXFpeWVmDggeERkFAM0AORIy+Eiza3tnRAAMtyL1EM5eQXq42UVVTN4XP3Hq+ubqS1q7QyFNMNnYyVXU2w7BeoG2YDgACMat9TqMLv9Jjd2PMHoMnhtZpxDrwVmsMcIgA – Ugur Eren Jan 13 '22 at 03:31
  • 1
    @UgurEren I think you should make it an answer! :-) – ghybs Jan 13 '22 at 03:49

2 Answers2

4

You can use this generic type, which takes a type and makes sure only all of them can exists or none of them can exists.

type AllOrNone<T> = Required<T> | Partial<Record<keyof T, undefined>>;

In your case, usage would be

export interface Name {
    firstName: string;
    lastName: string;
}

export type MyComponentProps = AllOrNone<Name>;

You can try it out in TS Playground

Ugur Eren
  • 1,968
  • 2
  • 11
  • 21
0

Embedding your group of props as an optional parent prop is indeed a straightforward solution. But it requires to pass an object to the prop when using the component.

You could alternatively try a union type to specify your props:

export type MyComponentProps = {} | {
  firstName: string;
  lastName: string;
}
ghybs
  • 47,565
  • 6
  • 74
  • 99
  • I saw something along the lines of 3 types `export type MyComponentRequiredProps { email: string;}\n export type MyComponentOptionalProps { firstName: string; lastName: string;}\n export type MyComponentProps extends MyComponentRequiredProps, MyComponentOptionalProps {}\n const myComponent: React.FC = (props) => { \n return
    \n } ` Is this the suggested way of doing that?
    – Thomas Jan 13 '22 at 03:17
  • I'm still kinda new in typescript and i was trying to find a solution to this question. I've tried your method in ts playground and seems like it doesn't work, or i'm missing something. It doesn't give any error when only one of them exists. https://www.typescriptlang.org/play?#code/LAKALgngDgpgBAOQIYFt4F44G9RzgMwEsAnAZzGTQC45zjCA7AcwG5c4AbJcymGuxq1ABfUKEiw4AIQD2YABYB5YghkMYAHgAqAPjiYswuAB84AJRgBHAK4kYAE2062IUAGM15OGo4QAYiQ8qHzSckoqapq8egbsRGQUwTQA5EjJADQiYiAeDF4+EAAy3InUoQrKquoa0frY7FxBZakZWa45nmBwDJE0shUR1bWxIHht7p1wAEZhfWGVkTXBMfWjBIGlIS2Za42bKWk7wkA – Ugur Eren Jan 13 '22 at 03:20
  • forgive the bad formatting, not sure how to use stackoverflow properly – Thomas Jan 13 '22 at 03:20
  • Yes it is exactly the same idea. The only difference is that in your comment example, there are also some props required in all cases. Can be writtemt as 3 types, or all in one like in my answer. – ghybs Jan 13 '22 at 03:21
  • As pointed out implicitly by @UgurEren, there is actually a limitation in union type checks unfortunately, which prevents above answer from throwing an error in case only some of the extra props are present. See https://stackoverflow.com/questions/46370222/why-does-a-b-allow-a-combination-of-both-and-how-can-i-prevent-it for more details. – ghybs Jan 13 '22 at 04:00
  • tested it but don't work for me (: – Duke May 24 '23 at 08:26