skip to Main Content

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?

2

Answers


  1. You need to handle the union logic manually after omitting the name prop. So, you can try to extract the conditional types into union and combine the results back to it.

    type OmitNameFromProps = (
      | Omit<{ name: string; age: number } & { education?: string; profession?: never }, 'name'>
      | Omit<{ name: string; age: number } & { education?: never; profession?: string }, 'name'>
    );
    

    So, you can use it as:

    export function Y(props: OmitNameFromProps) {
      return <X name="John" {...(props as Props)} />;
    }
    
    Login or Signup to reply.
  2. 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} />;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search