Search code examples
reactjstypescripttypescript-genericsreact-typescript

TypeScript combination of function props with generics


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.


Solution

  • 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');
    }
    

    Playground