I am trying to understand how I can enforce discriminated unions. I have a type definition that technically typescript will accept, but is not quite working as intended for me.
NOTE: I missed mentioning earlier that I need these type definitions for a functional component.
There is an official way to define a discriminated union. However, in an IDE, it will throw the following error:
Property 'startDate' does not exist on type 'MyComponentProps'.ts(2339)
Example that is accepted by typescript, but reflects an error in the IDE
import { FC } from "react";
interface BaseProps {
name: string;
age: number;
}
type IsEligibleProps = {
eligible: true;
startDate: string;
};
type NotEligibleProps = {
eligible: false;
reason: string;
};
type MyComponentProps = BaseProps & (IsEligibleProps | NotEligibleProps);
const MyComponent: FC<MyComponentProps> = ({
name,
age,
eligible = false,
startDate,
reason
}) => {
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
<p>Eligible: {eligible ? "true" : "false"}</p>
<p>Response: {eligible ? startDate : reason}</p>
</div>
);
};
export default MyComponent;
I have managed to find an inefficient solution that requires me to re-declare all the props for all the possible variants, but set the ones I do not need to null/never
.
Example that is accepted by typescript, and does not throw any errors
import { FC } from "react";
interface BaseProps {
name: string;
age: number;
}
type EligibleProps =
| {
eligible: true;
startDate: string;
reason?: never;
}
| {
eligible?: false;
reason: string;
startDate?: never;
};
type MyComponentProps = BaseProps & EligibleProps;
const MyComponent: FC<MyComponentProps> = ({
name,
age,
eligible = false,
startDate,
reason
}) => {
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
<p>Eligible: {eligible ? "true" : "false"}</p>
<p>Response: {eligible ? startDate : reason}</p>
</div>
);
};
export default MyComponent;
My question is - is there a way to use the original discriminated unions definition and have the Functional Component also read it, and determine the appropriate corresponding props on a de-structured props list?
Link to erroneous code
Link to working but inefficient code