As I work extensively with discriminated unions, a common issue arises:
When dealing with a function parameter that is a discriminated union type, I often need to perform specific actions based on subsets of the union.
Typically, I use the discriminant to narrow down the type, which works well initially.
The problem occurs when the union expands, resulting in lengthy
if (x.type === 'a' || x.type === 'b' || x.type === 'c' || ...)
chains.
In JavaScript, I'd handle this by using
if (['a','b','c'].includes(x.type))
, but TypeScript doesn't support this approach.
Consider the following example:
type Certificate = {
type: 'NATIONAL_ID',
nationality: string
} | {
type: 'PASSPORT',
passportNumber: string
} | {
type : 'INSURANCE_CARD',
provider: string
} | {
type: 'BIRTH_CERTIFICATE',
date: string
}| {
type: 'DEATH_CERTIFICATE',
date: string
}| {
type: 'MARRIAGE_CERTIFICATE',
date: string
}
// While functional, this method requires listing out each discriminant case
const goodPrintDate = (certificate: Certificate) => {
if (certificate.type === 'BIRTH_CERTIFICATE' || certificate.type === 'DEATH_CERTIFICATE' || certificate.type === 'MARRIAGE_CERTIFICATE') {
console.log(certificate.date)
return
}
console.log(`The certificate of type ${certificate.type} does not have a date`)
}
// Unfortunately, this attempt does not work as expected
const badPrintDate = (certificate: Certificate) => {
const certificateTypesWithDate = ['BIRTH_CERTIFICATE', 'DEATH_CERTIFICATE', 'MARRIAGE_CERTIFICATE']
if (certificateTypesWithDate.includes(certificate.type)) {
// The code only reaches here for specified types, but TS fails to infer it
console.log(certificate.date)
return
}
console.log(`The certificate of type ${certificate.type} does not have a date`)
}
Is there a more efficient way to structure goodPrintDate
without repeatedly enumerating every time? Perhaps by moving this logic to a separate function like (isCertificateWithDate / isCertificateTypeWithDate).
I've experimented with various solutions such as using sets instead of arrays, but nothing seems to be effective.