Melounek
Melounek

Reputation: 900

How to use "or" operator in Typescript with Omit<>?

This code:

type WithOr = {a:string} & ({b?:true, c?:never} | {b?:false, c:number})
type Ommited = Omit<WithOr, 'a'>
const m1: Ommited = {b: true};
const m2: WithOr = {...m1, a: 'a'}

will end up with error:

...
Type 'boolean | undefined' is not assignable to type 'false | undefined'.
...

It seems like Omit is throwing out the "or" logic.

Is there some other way how can I re-use my complicated type using Omit (with "or" in it), but not redefining everything?

Here is running playground

Upvotes: 0

Views: 395

Answers (1)

lukasgeiter
lukasgeiter

Reputation: 152890

This has to do with how Omit works. Here's how it is defined in lib.es5.d.ts:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Exclude<keyof T, K> produces a union of all keys except the ones you pass as K. So in your example that would be 'b' | 'c'.

Pick then uses a mapped type to iterate over these keys and create a new object type:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Because of this the type gets "flattened". In case of b, T['b'] returns true | false | undefined which TypeScript simplifies to boolean | undefined.

And you end up with:

type Ommited = {
    b?: boolean | undefined;
    c?: number | undefined;
}

I think the best thing you can do here is extract the "or" part into a named type and re-use that:

type OrPart = {b?:true, c?:never} | {b?:false, c:number}
type WithOr = {a:string} & OrPart
const m1: OrPart = {b: true};
const m2: WithOr = {...m1, a: 'a'}

Playground

Upvotes: 1

Related Questions