Union types do not work when combined with `Omit<>`

38 views Asked by At

I have the following interfaces:

export interface Base {
   a: string;
   b: string;
}

export interface Foo extends Base {
   c: string[];
   type: 'foo';
}

export interface Bar extends Base {
  c: string;
  type: 'bar';
}

From these interfaces I define the union type MyType in this way:

export type MyType = Foo | Bar;

The type MyType is thus inferred as:

{ 
  a: string;
  b: string;
  c: string | string[];
  type: 'foo' | 'bar';
}

which is the intended behavior. If I define a function like:

function testFunction1(param: MyType): MyType {
    return param;
}

It works fine, but when I replace MyType with Omit<MyType, 'b'> the compiler doesn't want to accept the code in any way. Example:

function testFunction2(param: Omit<MyType, 'b'>): MyType {
    return {...param, b: 'a'};
}

It returns the following error:

Type '{ b: string; c: string | string[]; type: "foo" | "bar"; a: string; }' is not assignable to type 'MyType'.

Type '{ b: string; c: string | string[]; type: "foo" | "bar"; a: string; }' is not assignable to type 'Bar'.

Types of property 'c' are incompatible. Type 'string | string[]' is not assignable to type 'string'. Type 'string[]' is not assignable to type 'string'.

Even if I'm sure that the returned value is compatible with MyType, since I'm changing a property defined in Base. How can I combine Omit and union types?

Note:

I'm trying to refine a type in a large codebase, for this reason, I don't want to force the type with a type assertion everywhere (e.g. return {...} as MyType). In the codebase there's a large use of Omit<> and when I refactored MyType in this way everything stopped working.

Typescript Playground

here

0

There are 0 answers