I've created a pipe
to convert any source to an Observable
, as follows:
// If T is like an Observable it infers the inner value, otherwise it returns T
type Unobservable<T> = T extends Observable<infer R> ? R : T;
@Pipe({
name: 'toObservable'
})
export class ToObservablePipe implements PipeTransform {
transform<T>(value: T): Observable<Unobservable<T>> {
return isObservable(value) ? value : just(value);
}
}
The functionality itself works, however I'm facing a problem with the return type. Currently it shows the following error:
Type '(T & Observable) | Observable' is not assignable to type 'Observable>'. Type 'T & Observable' is not assignable to type 'Observable>'. Type 'unknown' is not assignable to type 'Unobservable'.
Just to context you, the use of the pipe can be something like this:
<h4>Array source</h4>
<pre>{{ array | toObservable | async | json }}</pre>
How can I make compiler "happy"? :)
You can use an overload instead, as the @angular/AsyncPipe:
import { Pipe, PipeTransform } from '@angular/core';
import { isObservable, Observable, of as just } from 'rxjs';
@Pipe({
name: 'toObservable'
})
export class ToObservablePipe implements PipeTransform {
transform<T>(value: null): null;
transform<T>(value: undefined): undefined;
transform<T>(value: Observable<T> | null | undefined): Observable<T> | null | undefined;
transform<T>(value: T): Observable<T> | null | undefined;
transform(value: Observable<any> | null | undefined): any {
// can be also if (value === null || value === undefined) ...
if (value == null) return value;
return isObservable(value) ? value : just(value);
}
}
Some test cases:
const obj = { label: 1 };
// Error!
new ToObservablePipe().transform(null).subscribe(response => console.log(response));
// Error!
new ToObservablePipe().transform(undefined).subscribe(response => console.log(response));
// Inferred as string
new ToObservablePipe().transform('').subscribe(response => console.log(response));
// Inferred as number
new ToObservablePipe().transform(0).subscribe(response => console.log(response));
// Inferred as { label: number }
new ToObservablePipe().transform(just(obj)).subscribe(response => console.log(response));
// Inferred as { label: number }[]
new ToObservablePipe().transform([obj]).subscribe(response => console.log(response));
// Inferred as { label: number }
new ToObservablePipe().transform(obj).subscribe(response => console.log(response));