type-fest icon indicating copy to clipboard operation
type-fest copied to clipboard

MemberOfUnion

Open alita-moore opened this issue 1 year ago • 4 comments

I am using the following type and have found it useful:

type MemberOfUnion<Union, Member> = Union extends Member | infer Inferred
  ? Inferred extends Union
    ? false
    : true
  : true;
type Test1 = MemberOfUnion<undefined | string, undefined>; // Result: true
type Test2 = MemberOfUnion<string | number, undefined>; // Result: false
type Test3 = MemberOfUnion<undefined, undefined>; // Result: true
type Test4 = MemberOfUnion<string, undefined>; // Result: false
type Test5 = MemberOfUnion<number, undefined>; // Result: false
type Test6 = MemberOfUnion<null | undefined, undefined>; // Result: true
type Test7 = MemberOfUnion<null, undefined>; // Result: false
type Test8 = MemberOfUnion<boolean | undefined, undefined>; // Result: true
type Test9 = MemberOfUnion<boolean, undefined>; // Result: false
type Test10 = MemberOfUnion<object | undefined, undefined>; // Result: true
type Test11 = MemberOfUnion<object, undefined>; // Result: false
type Test12 = MemberOfUnion<unknown | undefined, undefined>; // Result: false
type Test13 = MemberOfUnion<unknown, undefined>; // Result: false

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • The funding will be given to active contributors.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

alita-moore avatar Sep 29 '23 19:09 alita-moore

seems like there are issues with this, though.

type MemberOfUnion<Union, Member> = Union extends Member | infer Inferred
  ? Inferred extends Union
    ? false
    : true
  : true;

type _A = MemberOfUnion<
  | undefined
  | {
  message: string;
},
  undefined
>

_A evaluates to false but I expect it to evaluate to true. Inferred seems to be including undefined for some reason

alita-moore avatar Sep 29 '23 19:09 alita-moore

this seems to be getting closer:

type MemberOfUnion<Union, Member> = Union extends Exclude<Union, Member>
  ? false
  : true;

alita-moore avatar Sep 29 '23 19:09 alita-moore

looks like Exclude isn't going to work for this, the following is working better for me now:

type MemberOfUnion<Union, Member> = Member extends Union
  ? true
  : [Union] extends [infer Inferred | Member]
  ? Union extends Inferred
    ? false
    : true
  : true;

alita-moore avatar Sep 29 '23 19:09 alita-moore

here's my example use case, btw:

export type MachineMessenger<
  Events extends string,
  EventPropsEnum extends MachineMessengerPropMap<Events>
> = {
  [key in Events]: EventPropsEnum[key] extends undefined
    ? () => void
    : MemberOfUnion<EventPropsEnum[key], undefined> extends true
    ? (props?: EventPropsEnum[key]) => void
    : (props: EventPropsEnum[key]) => void;
};

In this case I am checking to see if the type contains undefined, if it does I want the function to be able to called without a property. If not, then it requires a property.

alita-moore avatar Sep 29 '23 19:09 alita-moore