Reputation: 668
I am trying to make a 'switcher' of an unknown type coming from a database. Basically, there are certain calculation types that have a different data structure and need to be processed differently depending on the type. My first way to solve the problem was using conditionals:
type CalculationTypes = "add" | "average"
export interface Calculation<T extends CalculationTypes> {
calculationID: string // unique to all calculations
type: T
payload: T extends "add" ? CalculationAdd : CalculationAverage
}
interface CalculationAdd {
addlist: {referenceContainer: string, referenceID: string}[]
}
interface CalculationAverage {
averageList: number[]
}
This worked - kind of - because the type wasn't being detected later in the script. I had to infer it, which isn't so bad, but I'm sure there's a better way to do it where the transpiler can automatically deduce the type...
Then later in the script:
for (const calculation of dbresult.calculations) {
switch(calculation.type) {
case "add":
const payload = calculation.payload as CalculationAdd // <--- this is what I want it to do automatically.
/** The transpiler does not detect it. It thinks that payload is of
type CalculationAdd | CalculationAverage **/
payload.addList // do stuff works now with type inference
// do more stuff
break;
case "average":
const payload = calculation.payload as CalculationAverage
payload.averageList // do stuff
// do more stuff
break;
}
}
Without type inference, typescript gives me the error:
Property 'addList' does not exist on type 'CalculationAdd | CalculationAverage'.
Property 'addList' does not exist on type 'CalculationAverage'
So for some reason, typescript has not deduced that it has to be of type CalculationAdd without type inference, even though that's the only possibility given the conditional I set up in the Calculation interface.
How can I change the way I'm defining these types and interfaces so that typescript automatically deduces them?
Thanks!
Upvotes: 2
Views: 231
Reputation: 1405
Typescript is actually capable of doing this. See this explanation, I think it's very similar with your use-case.
I think your problem comes from the fact that you've defined the same variable payload
in both switch-case branches. Either try to rename the payload
in the second case, or just wrap your switch-case branches in curly brackets, { ... }
.
Here's the code that works for me:
for (const calculation of dbresult.calculations) {
switch (calculation.type) {
case "add": {
const {payload} = calculation; // <--- automatically inferred by TS
payload.addlist // do stuff works now with type inference
console.log(payload);
break;
}
case "average": {
const {payload} = calculation;
payload.averageList // do stuff
console.log(payload);
break;
}
}
}
Upvotes: 1