I have some interfaces that extend from a base:
enum eItemType { /* … */ }
interface Item {
someCommonKeyValPairCollection: eItemType;
type: eItemType;
weight: number;
// …
}
interface ItemTypeA extends Item {
someKeyValPairCollection: eItemType;
}
interface ItemTypeB extends Item {
someOtherKeyValPairCollection: eItemType;
}
type tItem = Item | ItemTypeA | ItemTypeB
And then I have a method that receives an Item, but it could be a (non-keyword) generic Item or ItemTypeA or ItemTypeB, so I created the union type tItem. The method does some common things, and then some specific things based on item.type (looping through either someKeyValPairCollection or someOtherKeyValPairCollection. Typescript freaks out, throwing half a dozen assignment errors, ex Property 'someKeyValPairCollection' is missing in type Item (no shit).
The method looks roughly like this:
processItem(item: tItem): boolean {
const isValid: boolean = checkValidity(item);
if (!isValid) return false;
_.each(someCommonKeyValPairCollection, () => { /* do some common stuff */ });
// if (typeof item.someKeyValPairCollection !== 'undefined') // tried first, doesn't like
if (item.type === eItemType.a) processA(item.someKeyValPairCollection);
return true;
}
How is one supposed to handle if (item.type === eItemType.a) // do some special stuff?
You need to use a discriminated union. A union where one property (
typein this case) has a specific value for a particular type. You can read more about the topic hereEdit
Added a simple alternative to have a catch the rest of the enum values without having to define a separate type for each enum value or having to list them individually.