Home > Net >  How to access all properties when BehaviorSubject declared with multiple interfaces?
How to access all properties when BehaviorSubject declared with multiple interfaces?

Time:09-27

I have several interfaces as below:

export interface INT1 {
   prop1: string;
   prop2: string;
}

export interface INT2 {
   prop1: string;
   prop3: string;
}

export interface INT3 {
   prop1: string;
   prop4: string;
}

Now I am trying to declare a BehaviorSubject that returns one of the three interfaces above:

private _mySub$ = new BehaviorSubject<INT1 | INT2 | INT3>(undefined);

This doesn't work, because if I access the BehaviorSubject value, I only find the shared properties (in this case only prop1). What am I doing wrong?

CodePudding user response:

There is nothing wrong with the code. Since _mySub$ could be a BehaviorSubject of type INT1, INT2, or INT3, static analysis can only guarantee that _mySub$ has property prop1 in all cases. It would be incorrect to infer the existence of other properties without narrowing the type.

If you know for a particular context that the BehaviorSubject will always return exactly one of the interfaces, then you could use a more specific declaration such as:

private _mySub$ = new BehaviorSubject<INT1>({prop1: '1', prop2: '2'});

Type Guards

A common solution for handling broad type-definitions is to use TypeScript Type Guards.

Example: User-defined Type Guard for INT1

function instanceOfINT1(object: any): object is INT1 {
  return 'prop2' in object;
}

Using the type guard, you could safely access prop2 when the BehaviorSubject emitted an INT1:

class MyClass {
  private _mySub$ = new BehaviorSubject<INT1 | INT2 | INT3>({prop1: '1', prop2: '2'});

  constructor() {
    this._mySub$.subscribe( (val) => {
      if (instanceOfINT1(val)) {
        console.log(`val.prop2: ${val.prop2}`);
      }
    });
  }
}

CodePudding user response:

Firstly you could declare a "base" interface with shared prop1 property.

export interface BASE {
   prop1: string;
}

export interface INT2 extends BASE {
   prop3: string;
}

export interface INT3 extends BASE {
   prop4: string;
}

Secondly, you can use typescript assertion:

const int3: INT3 = obj as INT3;

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions

  • Related