I have an object with two values. I would like to type check one value conditionally based on the value of its peer. I have looked at various solutions but I cannot get it to work how I would like it to.
I can do something like this (source):
type TypeFruit = "apples" | "bananas";
type TypeMetal = "iron" | "copper";
type InterfaceItem =
| {
item: "fruit";
type: TypeFruit;
}
| {
event: "metal";
type: TypeMetal;
};
type ItemTypeParameters = InterfaceItem["type"];
type Item = {
item: "fruit" | "metal";
type: ItemTypeParameters;
};
But that produces:
// ✅ Correct
assignItem({
item: "fruit",
type: "apples",
});
// ✅ Correct
assignItem({
item: "fruit",
type: "copper",
});
What I would like to do is set up the code so that the outcome would be like this:
// ✅ Correct
assignItem({
item: "fruit",
type: "apples",
});
// ❌ Wrong
assignItem({
item: "fruit",
type: "copper",
});
Is there a way to do this? I've looked at ConditionalTypes, which seems like what I would want, but found them confusing and it seemed like they were for other scenarios like extending types conditionally.
CodePudding user response:
Your original InterfaceItem
is already giving you the shape you're looking for - where item: "fruit"
is necessarily paired with (and only paired with) a TypeFruit
. All you need is that, and nothing else.
type TypeFruit = "apples" | "bananas";
type TypeMetal = "iron" | "copper";
type InterfaceItem =
| {
item: "fruit";
type: TypeFruit;
}
| {
event: "metal";
type: TypeMetal;
};
declare const assignItem: (item: InterfaceItem) => null;
assignItem({ // Works
item: "fruit",
type: "apples",
});
assignItem({ // Fails
item: "fruit",
type: "copper",
});