简体   繁体   中英

Merge or operator in object Typescript

How to get rid of or operator ( | ) and merge all object properties to be all accessible?

Because now, typing payload.signInMethod TS complaints that this method does not exist in none "or group" but this one. How to write type to merge all object keys?

删除 ors

Desired object: 在此处输入图像描述

Playground to reproduce my problem: https://www.typescriptlang.org/play/#code/C4TwDgpgBAwg9gO2BAHsKBeKBvAUFKAUQDcIkBBMMAGwEsBjAQ2FsQC4d8CpGq6mWiAAoALRgGcIHccABOtBAHMA3FwC+qggGVaihAEkEAJQgAzDnm5RxugwgCyEYCLgATDgHJFcOIuoQPKAAfKA9TRnoIACMfAGtAkI8QRhc4BNCAV0lZBEYAWwDNKA0uQhQwWQhxcRgRCHpYuAzgCy4CMEYQAqRHZzchSskkDhi4f0YEIoJxEVoqBUVyV1dB8QGqshaoUfHJtqhKyNpSIUZZYAQIWUI8xlpqcRGfXamoCrg8uHhXKWs5BaKalwQNw9EQMigiic8CQqHQWAAFB0QNQ4Ix3LBEMg0ABtWIQEBwUyY2FoAC6AEpMAA+TjtTqo9EAOhsekMvRcrmUUAA9DyoAAJOAAdygwDgkKcB1origRLFs3EUCusjgsmBQA

The usual way to deal with union types is to use type guards to narrow the union down to one of the members. In this case the in type guard works best:

type Context = {
  EventApplication: {
    applicationPhase: string;
  };
  SignInRef: {
    signInMethod: 'google' | 'facebook' | 'yahoo' | 'username';
  };
  ExpressCheckout: {
    paymentMethodPresent: boolean;
    shippingAddressPresent: boolean;
    receivePartnerEmails: boolean;
    promoCode: string;
  }
}

const getContext = (payload: Context[keyof Context]) => {
  if('signInMethod' in payload) {
    payload.signInMethod; 
  } else if('applicationPhase' in payload) {
    payload.applicationPhase
  } else{
    payload.promoCode
  }
}

Play

Now if you really want to have access to all members directly on payload , some | undefined | undefined will by necessity have to creep into the property types (since a property might be undefined on a specific union member). We can adapt StrictUnion from here to get the types to work the way you want:

type UnionKeys<T> = T extends any ? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, undefined>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>

type Context = {
  EventApplication: {
    applicationPhase: string;
  };
  SignInRef: {
    signInMethod: 'google' | 'facebook' | 'yahoo' | 'username';
  };
  ExpressCheckout: {
    paymentMethodPresent: boolean;
    shippingAddressPresent: boolean;
    receivePartnerEmails: boolean;
    promoCode: string;
  }
}

const getContext = (payload: StrictUnion<Context[keyof Context]>) => {
  payload.applicationPhase // string | undefined 
}

Play

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM