ehutchllew
ehutchllew

Reputation: 958

Trying to make presence of at least one optional parameter required, but its presence excludes the others

so let me dive into an example:

type NodeOrMethod<T> =
    | {
          node?: Array<Filter<T>>;
          method: Condition<T>;
      }
    | {
          node: Array<Filter<T>>;
          method?: Condition<T>;
      };

interface BaseFilter {
    label: string;
    value?: string;
}

export type Filter<T> = BaseFilter & NodeOrMethod<T>;

Basically what I want to do is make it so the dev has to either include node or method - which this currently works; however, I want to take it a step further and say IF one of these is present the other CANNOT be. So if they try to include both node and method in the same object it would complain. Has anyone done something like this before?

Upvotes: 0

Views: 563

Answers (2)

bugs
bugs

Reputation: 15313

I would probably use tagged unions (see the relevant section of the docs) for what you are trying to do, something like

type Node<T> = {
    type: 'node',
    node: Array<Filter<T>>;
}
type Method<T> = {
    type: 'method',
    method: Condition<T>;
}
type NodeOrMethod<T> = Node<T> | Method<T>;

cost a: NodeOrMethod<T> = { // valid
  type: 'node',
  node: [...]
}

cost b: NodeOrMethod<T> = { // valid
  type: 'method',
  method: ...
}

cost c: NodeOrMethod<T> = { // type error
  type: 'method',
  node: [...],
  method: ...
}

Example

Upvotes: 2

ChiralMichael
ChiralMichael

Reputation: 1224

Node/JS philosophy doesn't really work this way. Objects are given permission to have whatever they want on them and consuming code only pays attention to what it cares about. Some ways to handle this include:

  • Use factory methods to ensure proper instantiation of your objects
  • Have a "type" property that indicates whether to look at the node or the method

All the same, the type is suspiciously overloaded with two meanings. I expect there is another pattern available that avoids this. If you're stuck in a corner with code that is not yours, then one of the above approaches should work fine.

Upvotes: 0

Related Questions