Home > database >  Possible for typescript type to have a required field, but be optional on "constructor"?
Possible for typescript type to have a required field, but be optional on "constructor"?

Time:01-12

Attempting to have a Type with required fields, as each field is necessary, but default one of the parameters so I don't have to type it every time. For example:

export type Notification = {
  title: string
  message: string
  category: 'good' | 'bad'
}

const notifications: Notification[] = []

export const notify = (notification) => {
  notifications.push(notification)
}

So for the psuedo-constructor, at first it seems having Notification would be a good type for the input.

export const notify = (notification: Notification) => {
  notifications.push(notification)
}

But, what if the category will be good the vast majority of the time? Then I would want to make the category key optional on the function, and default it to good. However, due to the typing, category is required. How do I get around this?

I could create a new type:

export type NotifyInput = {
  title: string
  message: string
  category?: 'good' | 'bad'
}

export const notify = (notification: NotifyInput) => {
  notifications.push({
    ...notification,
    category: notification.category ?? 'good'
  })
}

but this isn't DRY at all, and I don't want to have to change multiple spots in the same file. Since i'm exporting the function, I can use it anywhere, so I don't want to have to export both types as well. I could also just inline the type on the function, but it has the same problems as before.

Sadly, I have to do one of the two sub-optimal options or my typescript compiler complains about notification being type any OR not containing category.

There has to be a better way than this. What is it?

CodePudding user response:

How about something like this? You specify the input type with an optional category and then export the Notification type with all properties required. Here's a working playground.

type NotificationInput = {
  title: string
  message: string
  category?: 'good' | 'bad'
}

export type Notification = Required<NotificationInput>;

const notifications: Notification[] = []

export const notify = (notification: NotificationInput) => {
  notifications.push({
    ...notification,
    category: notification.category || 'good'
  })
}
  • Related