Home > Net >  Conditional Type in Typescript based on another Type
Conditional Type in Typescript based on another Type

Time:09-13

I'm having issues with conditional types.

I require that when filter[triggerType] on AutomationParams changes, filter[triggerId] values also update to the proper kind.

For instance, when filter[triggerType] equals corn, the alternatives for filter[triggerId] are limited to being of the CronTriggerId type.

 type TriggerType = 'event' | 'cron' | 'scheduled';

 type EventTriggerId = 'extendStayRequired' | 'reservationAccessChanged'

 type CronTriggerId = 'reservationsCron';
 
 type ScheduledTriggerId = 'reservationCheckedIn';


 type TriggerId<T> = T extends 'event'
  ? EventTriggerId
  : T extends 'cron'
  ? CronTriggerId
  : T extends 'scheduled'
  ? ScheduledTriggerId
  : never;

 type AutomationParams = {
  'filter[triggerType]': TriggerType;
  'filter[triggerId]': TriggerId<TriggerType>;
};

const obj: AutomationParams = {
  'filter[triggerType]': 'cron',
  'filter[triggerId]': 'extendStayRequired',
};

Additionally, this is the playground.

CodePudding user response:

I would suggest to rewrite TriggerId to just be a simple lookup map.

type TriggerMap = {
  event: EventTriggerId
  cron: CronTriggerId
  scheduled: ScheduledTriggerId
}

AutomationParams can now be calculated to be a union of all valid combinations.

type AutomationParams = {
  [K in keyof TriggerMap]: {
    'filter[triggerType]': K;
    'filter[triggerId]': TriggerMap[K];
  }
}[keyof TriggerMap]

Playground

CodePudding user response:

AutomationParams should itself be a union :

 type EventTriggerId = 'extendStayRequired' | 'reservationAccessChanged'
 type CronTriggerId = 'reservationsCron';
 type ScheduledTriggerId = 'reservationCheckedIn';


 type AutomationParams = {
  'filter[triggerType]': 'event';
  'filter[triggerId]': EventTriggerId;
} | {
  'filter[triggerType]': 'cron';
  'filter[triggerId]': CronTriggerId;
} | {
  'filter[triggerType]': 'scheduled';
  'filter[triggerId]': ScheduledTriggerId;
};

const obj: AutomationParams = {
  'filter[triggerType]': 'scheduled',
  'filter[triggerId]': 'reservationCheckedIn',
};

console.log(obj)

Or use mapping interface :

 type TriggerType = 'event' | 'cron' | 'scheduled';
 
 type EventTriggerId = 'extendStayRequired' | 'reservationAccessChanged'
 type CronTriggerId = 'reservationsCron';
 type ScheduledTriggerId = 'reservationCheckedIn';


export interface AutomationParams<T extends TriggerType> {
    'filter[triggerType]': T
    'filter[triggerId]': TriggerId[T]
}
type TriggerId ={
    'event': EventTriggerId,
    'cron': CronTriggerId,
    'scheduled': ScheduledTriggerId

}

const obj: AutomationParams<'event'> = {
  'filter[triggerType]': 'event',
  'filter[triggerId]': 'extendStayRequired',
};

console.log(obj)

You could also do it with conditional types:

type TriggerType = 'event' | 'cron' | 'scheduled';

 type EventTriggerId = 'extendStayRequired' | 'reservationAccessChanged'

 type CronTriggerId = 'reservationsCron';
 
 type ScheduledTriggerId = 'reservationCheckedIn';


 type TriggerId<T> = T extends 'event'
  ? EventTriggerId
  : T extends 'cron'
  ? CronTriggerId
  : T extends 'scheduled'
  ? ScheduledTriggerId
  : never;

 type AutomationParams<T extends TriggerType> = {
  'filter[triggerType]': T;
  'filter[triggerId]': TriggerId<T>;
};

const obj: AutomationParams<'cron'> = {
  'filter[triggerType]': 'cron',
  'filter[triggerId]': 'reservationsCron',
};
  • Related