Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to Exclude an empty object from a union?

I have a union of two types, one of which is an empty obj.

type U = {} | { a: number } // | { b: string } | { c: boolean } ....

I would like to exclude the empty object from the union however Exclude is no help

type A = Exclude<U, {}>
// A = never

I tried using as const but it's the same result

const empty = {} as const
type Empty = typeof empty
type U = Empty | { a: number }
type A = Exclude<U, Empty>
//type A = never

The extra Irony is that excluding the other properties is straightforward

  type B = Exclude<U, { a: number }>
  // type B = {}

TS Playground

So is it possible to exclude an empty interface from other interfaces in a union?

like image 687
lonewarrior556 Avatar asked Apr 24 '20 14:04

lonewarrior556


2 Answers

Answering my own question..

If you use AtLeastOne from @lukasgeiter answer here: Exclude empty object from Partial type

you can do the following:

type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
    
type ExcludeEmpty<T> = T extends AtLeastOne<T> ? T : never; 
    
type U = {} | { a: number } | { b: string }
    
type Foo = ExcludeEmpty<U> // { a: number } | { b: string }

TSplayground

like image 90
lonewarrior556 Avatar answered Oct 19 '22 21:10

lonewarrior556


From the docs for conditional typing here, you can actually assign types based on some condition.

T extends U ? X : Y

So for the above question, what you could do is make use of keyof keyword that is used to extract keys from objects. When there is no any keys found the type is never so, we can check if the keyof object extends never or not i.e.

 keyof K extends never

So combing conditional typing below;

const empty = {} as const
type Empty = typeof empty

type NoEmpty<K> = keyof K extends never ? never : K;

type C = NoEmpty<Empty>;

type U = NoEmpty<Empty> | NoEmpty<{ a: number }>

You can finally see that type of the U to be non empty object i.e excluding empty object. Check this playground

like image 3
Dipesh Dulal Avatar answered Oct 19 '22 21:10

Dipesh Dulal