The point of this Type is to allow user to pass in either data, color, hasColor or data, info, hasInfo. Not any other combination.
type Props = {
data: string;
} & (
| {
info?: string;
hasInfo?: boolean;
color?: never;
hasColor?: never;
}
| {
info?: never;
hasInfo?: never;
color?: string;
hasColor?: boolean;
}
);
function foo(props: Props) {
console.log("bar");
}
foo({ data: "hello", info: "hello", hasInfo: true }); <----- TypeScript is happy
foo({ data: "hello", info: "hello", hasColor: true }); <----- TypeScript gives Error
Is there a cleaner way to implement this behavior using generics?
I tried this, but it looks like I'm messing up the logic of the ternary somehow:
type Info = { info: string; hasInfo: boolean };
type Color = { color: string; hasColor: boolean };
type Data = { data: string };
function foo<T>(
props: keyof T extends keyof Info ? Data & Info : Data & Color
) {
console.log("bar");
}
foo({ data: "hello", color: "hello", hasColor: true }); <----TypeScript gives Error
The first way works but looks so ugly.
After playing around I found another solid solution:
type Info = { info?: string; hasInfo?: boolean };
type Color = { color?: string; hasColor?: boolean };
type Data = { data: string };
function foo<T>(
props: keyof Info extends keyof T
? Exclude<T, Color> & Data & Info
: Exclude<T, Info> & Data & Color
) {
console.log('bar');
}