Search code examples
reactjstypescript

Spreading props with conditional props after omitting


I have a component which conditionally accepts either of two props using never like this:

type Props = {
  name: string;
  age: number;
} & (
  | {
      education?: string;
      profession?: never;
    }
  | {
      education?: never;
      profession?: string;
    }
);

export function X(props: Props) {
  return null;
}

Now if I have another component that reuses this first component but with omitting a property like name like so:

export function Y(props: Omit<Props, 'name'>) {
  return <X name="John" {...props} />;
}

I get the following error:

Type '{ age: number; education?: string | undefined; profession?: string | undefined; name: string; }' is not assignable to type 'IntrinsicAttributes & Props'.
  Type '{ age: number; education?: string | undefined; profession?: string | undefined; name: string; }' is not assignable to type '{ education?: undefined; profession?: string | undefined; }'.
    Types of property 'education' are incompatible.
      Type 'string | undefined' is not assignable to type 'undefined'.
        Type 'string' is not assignable to type 'undefined'. 

If I remove the Omit, it works.

How can I omit a prop from props containing conditional props such as in the example?


Solution

  • Conditional type OmitName to ensure that when omitting name. TypeScript preserves the mutually exclusive logic between education and profession without breaking their type constraints:

    type Props = {
      name: string;
      age: number;
    } & (
      | {
          education?: string;
          profession?: never;
        }
      | {
          education?: never;
          profession?: string;
        }
    );
    
    
    type OmitName<T> = T extends { name: any } ? Omit<T, 'name'> : T;
    
    export function X(props: Props) {
      return null;
    }
    
    export function Y(props: OmitName<Props>) {
      return <X name="John" {...props} />;
    }