When defining a type, can we make one property required based on another property?
An example is:
type Parent = {
children?: Child[];
childrenIdSequence: string[]; // Only make this required when `children` is given
}
What you want can be achieved using a union type:
type Parent = {
children: Child[],
childrenIdSequence: string[]
} | {
children: undefined
}
This means a Parent either has a children array and a childrenIdSequence array, or its children property is undefined and it is not guaranteed to have a childrenIdSequence array. The type can be control-flow narrowed by testing the children property:
function test(p: Parent): void {
if(p.children) {
// p: { children: Child[], childrenIdSequence: string[] }, so OK
console.log(p.childrenIdSequence);
} else {
// p: { children: undefined }, so type error
console.log(p.childrenIdSequence);
}
}
However, there is a bit of a downside: the children property is required even if you want it to be undefined. You have to explicitly write a literal like { children: undefined } instead of just {}, otherwise it won't be of type Parent.
If you try declaring the type with children?: undefined as an optional property, then the union won't work because one branch is a structural subtype of the other, and the type in the function will be uselessly narrowed to p: never.