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