Reputation: 900
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
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'}
Upvotes: 1