I have the following function that takes either of 3 types that all share 1 property in common, but their other properties vary:
private async processPredicates(
routing: ActivityRouting[] | ActivityStepOptionsOverride[] | ActivityStepContentSource[]
) {
for (const { predicate, ...block } of routing) {
if (predicate == null) return block;
else if (await this.callMethod(PREDICATES, predicate)) return block;
}
return null;
}
The property that all 3 types share is called predicate
export type ActivityRouting = {
predicate?: string[];
sideEffects?: SideEffect[];
next?: Next;
};
export type ActivityStepOptionsOverride = {
mode?: string;
predicate?: string[];
};
export type ActivityStepContentSource = {
reduce?: string;
use?: string;
predicate?: string[];
};
Now here's my problem - after adding the second and third type to processPredicates, the following function started giving me 2 errors:
private async resolveRouting({
routing,
step,
options,
defaultNext,
}: {
routing?: ActivityRouting[];
step: ActivityStep;
options: ActivityStepOptions;
defaultNext: Next;
}) {
await StepEvaluationContext.evaluate({ controller: this, step, options }, async () => {
const leftoverRouting = routing && (await this.processPredicates(routing));
if (leftoverRouting && leftoverRouting.sideEffects) {
await Promise.all(
leftoverRouting.sideEffects.map(
async (sideEffect) => await this.callMethod(SIDE_EFFECTS, sideEffect)
)
);
}
await this.callMethod(STEP_RESOLVERS, leftoverRouting?.next ?? defaultNext);
});
}
The errors are:
Property 'sideEffects' does not exist on type '{ sideEffects?: SideEffect[] | undefined; next?: Next | undefined; } | { reduce?: string | undefined; use?: string | undefined; } | { mode?: string | undefined; }'.
Property 'sideEffects' does not exist on type '{ reduce?: string | undefined; use?: string | undefined; }'.ts(2339)
And
Property 'next' does not exist on type '{ sideEffects?: SideEffect[] | undefined; next?: Next | undefined; } | { reduce?: string | undefined; use?: string | undefined; } | { mode?: string | undefined; }'.
Property 'next' does not exist on type '{ reduce?: string | undefined; use?: string | undefined; }'.ts(2339)
I imagine the error stems from the fact that the function resolveRouting doesn't know which of the 3 types leftoverRouting, so it just tells me that the property doesn't exist. I'm not quite sure how to handle that problem though.
The problem is that the return type of processPredicates function has the union of all 3 types. It's not possible to access leftoverRouting.sideEffects without a type narrowing it.
To solve it make processPredicates a generic function that returns the type being called instead. It would be the following:
interface Activity {
predicate?: string[];
}
export interface ActivityRouting extends Activity {
sideEffects?: string[];
next?: string;
};
export interface ActivityStepOptionsOverride extends Activity {
mode?: string;
};
export interface ActivityStepContentSource extends Activity {
reduce?: string;
use?: string;
};
async function processPredicates<T extends Activity>(
routing: T[]
): Promise<Omit<T, 'predicate'> | null> {
for (const { predicate, ...block } of routing) {
if (predicate == null) return block;
else if (await this.callMethod(PREDICATES, predicate)) return block;
}
return null;
}