Home > Net >  Optional field in TypeScript based on if a field exists
Optional field in TypeScript based on if a field exists

Time:12-25

I have this interface:

export interface AuthBtn {
    link: string,
    text: string,
    onClick: (p1?: object, p2?: object)=> void,
}

And either the link or onClick field will exist, and I want the interface to only include either link & text or onClick & text

How can I acheive this?

CodePudding user response:

You need a discriminated union.

export type AuthBtn =
  | {
    link: string,
    text: string,
    _tag: "link_text",
  } 
  | {
    onClick: (p1?: object, p2?: object)=> void,
    text: string,
    _tag: "onclick_text",
  }

The discriminant is not strictly necessary, but really useful in lots of situations.

CodePudding user response:

You need a union, like

export type AuthBtn1 =
  | {
    text: string,
    onClick: (p1?: object, p2?: object) => void,
  } | {
    text: string,
    link: string,
  }

declare let a1: AuthBtn1;
if ('link' in a1) {
  a1
  // ^?
  // let a1: {
  //   text: string;
  //   link: string;
  // }
}

If you don't like using in operatorm you need a distinct union

export type AuthBtn2 =
  | {
    text: string,
    onClick: (p1?: object, p2?: object) => void,
    link?: never,
  } | {
    text: string,
    link: string,
    onClick?: never,
  }

declare let a2: AuthBtn2;
if (a2.link) {
  a2
  // ^?
  // let a2: {
  //   text: string;
  //   link: string;
  //   onClick?: undefined;
  // }
}

(| in the beginning is noop, just for aligning)

  • Related