Reputation: 3889
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
}
Upvotes: 2
Views: 2844
Reputation: 51034
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
.
Upvotes: 3