When working inside a .forEach
loop, I am encountering an issue with narrowing down a type (the last statement in the snippet below).
Within that loop, TypeScript interprets that obj
is either of type ObjA | ObjB
(since TypeScript created a union of all possible values for that key in the array), while the method requires ObjA & ObjB
(because TypeScript listed possible arguments and created an intersection). These types are not the same.
Despite this discrepancy, the code is correct as the elements' obj
and cls
keys from the array match and can be used together:
type ObjBase = { id: string };
abstract class Base<T extends ObjBase> {
abstract processObj(obj: T): string;
useObj(obj: T) {
return this.processObj(obj);
}
}
// Module A
type ObjA = { someKey: string } & ObjBase;
class DerivedA extends Base<ObjA> {
processObj(obj: ObjA): string {
return obj.id + obj.someKey;
}
}
// ========
// Module B
type ObjB = { otherKey: string } & ObjBase;
class DerivedB extends Base<ObjB> {
processObj(obj: ObjB): string {
return obj.id + obj.otherKey;
}
}
// ========
const modules = [
{ obj: { id: 'a', someKey: '' } as ObjA, cls: new DerivedA() },
{ obj: { id: 'b', otherKey: '' } as ObjB, cls: new DerivedB() },
] as const;
modules.forEach(module => {
module.cls.processObj(module.obj);
});
To resolve the error within the .forEach
, how can I communicate to TypeScript that it is safe?
The objective is to have multiple 'modules' in the application that reuse a significant amount of code (represented by Base#useObj
and operations within the forEach
loop). Perhaps there is a better way to structure my components that I am overlooking?
Please note that I want to avoid referencing individual module entities inside the loop, as it would contradict the aim of conforming them to a single interface.