I would like to hide the "next" interface of a BehaviorSubject while retaining its other properties, especially the possibility to get last emitted value imperatively. The idea is all state manipulation can be done on a private BehaviorSubject within a service and all I expose is what I would call a "ReadonlySubject" that does not have "next" method. The only idea I have so far is something like this:
export class ReadonlyBehaviorSubject<T> extends BehaviorSubject<T> {
override next(_value: T) {
console.error('cannot set value on a readonly BehaviorSubject');
}
}
export function toReadonlyBehaviorSubject<T>(bs: BehaviorSubject<T>): ReadonlyBehaviorSubject<T> {
return new ReadonlyBehaviorSubject(bs.value);
}
As you can see we still have "next" method - it just does nothing, but informs the user that they cannot set a value on ReadonlyBehaviorSubject. Is there something neater? Preferably not exposing "next" method at all?
You are just overriding the next method, so it is still available. The correct way would to omit "next". Create a type instead:
export type ReadonlyBehaviorSubject<T> = Omit<BehaviorSubject<T>, 'next'>;
Then use it like:
private data = new BehaviorSubject<string>('some value');
public readonly data$: ReadonlyBehaviorSubject<string> = this.dataSubject;
But as mentioned in comments, what I usually do is to have the subject as private and expose an observable to subscribe to:
private data = new BehaviorSubject<string>('some value');
public data$ = this.data.asObservable();