Home > database >  typescript: how to make a type depend on a field value
typescript: how to make a type depend on a field value

Time:01-17

I have a structure like the following, and I want details to be a CardType when method_type equals 'card', and to be a SepaDetail when it's sepa.

How can I have typescript enforce this?

type PaymentMethod = {
  id: string,
  provider: Provider,
  holder_name: string,
  [more fields...],
  method_type: "card" | "sepa",
  details: CardDetails | SepaDetails
}

type CardDetails = {
  brand: string,
  last_digits: string
}

type SepaDetails = {
  last_digits?: string
}

see this typescript playground

CodePudding user response:

You can do that with a union of object types:

type PaymentMethod = {
  id: string,
  method_type: 'card',
  details: CardDetails,
} | {
  id: string,
  method_type: 'sepa',
  details: SepaDetails
}

If you have a lot of fields in common that you don't want to repeat, then you can either use an interface that you extend:

interface BasePaymentMethod {
  id: string,
  [more fields...],
  method_type: 'card' | 'sepa'
}

interface CardPaymentMethod extends BasePaymentMethod {
  method_type: 'card',
  details: CardDetails,
}

interface SepaPaymentMethod extends BasePaymentMethod {
  method_Type: 'sepa'
  details: SepaDetails
}

type PaymentMethod = CardPaymentMethod | SepaPaymentMethod

Or if you prefer types instead of interfaces, you can do intersections (&):

type BasePaymentMethod = {
  id: string,
  [more fields...],
  method_type: 'card' | 'sepa'
}

type CardPaymentMethod = BasePaymentMethod & {
  method_type: 'card',
  details: CardDetails,
}

type SepaPaymentMethod = BasePaymentMethod & {
  method_Type: 'sepa'
  details: SepaDetails
}

type PaymentMethod = CardPaymentMethod | SepaPaymentMethod

CodePudding user response:

I think I found a way:

type PaymentMethod = {
  id: string,
  [bunch of other fields...],
} & (CardDetails | SepaDetails)

type CardDetails = {
  method_type: "card",
  details: {
    brand: string,
    last_digits: string
  }
}

type SepaDetails = {
  method_type: "sepa",
  details: {
    last_digits?: string
  }
}

const pm1: PaymentMethod = {
  id: '1',
  method_type: 'card',
  details: {
    brand: 'zz',
    last_digits: 'xxx'
  }
}

const pm2: PaymentMethod = {
  id: '1',
  method_type: 'sepa',
  details: {
    last_digits: 'xxx'
  }
}

see ts playground

  • Related