使用推断来获取装箱的 Observable 值

Using infer to grab the boxed Observable value

我创建了一个 pipe 来将任何源转换为 Observable,如下所示:

// 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);
  }
}

功能本身有效,但我遇到了 return 类型的问题。目前它显示以下错误:

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'.

只是为了给你介绍一下,管道的使用可以是这样的:

<h4>Array source</h4>

<pre>{{ array | toObservable | async | json }}</pre>

如何制作编译器"happy"? :)

DEMO

通过这种方式,您可以在不使用推断的情况下获得相同的结果。

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: T): T | Observable<T> {
    return isObservable(value) ? value : just(value);
  }
}

但如果你想使用推断,我可以建议你这个解决方案

import { Pipe, PipeTransform } from "@angular/core";
import { isObservable, Observable, of as just } from "rxjs";

type Unobservable<T> = T extends Observable<infer R> ? R : T;
type ObservableOrAny<T> = Observable<T> | T;

@Pipe({
  name: "toObservable"
})
export class ToObservablePipe implements PipeTransform {
  transform<T>(value: ObservableOrAny<T>): Observable<Unobservable<ObservableOrAny<T>>> {
    return isObservable(value) ? value : just(value);
  }
}
type Unobservable<T> = T extends Observable<infer R> ? R : T;

意味着 Unobservable 可以传递 <T> 的类型,或者 any 因为 R 可以是某种未知类型。

这里 transform<T>(value: T): Observable<Unobservable<T>> 您希望 return 与转换类型相同,但情况并非总是如此,因为我们声明它可以是 any 类型并询问推断它。

要让您的工作发挥作用,请输入 transform response to any。

Observable<Unobservable<any>>

Unobservable到底是什么类型,我不明白它的用途

import { Pipe, PipeTransform } from "@angular/core";
import { isObservable, Observable, of as just } from "rxjs";

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 as Observable<Unobservable<T>> : 
just(value) as Observable<Unobservable<T>>;
  }
}

只要你想要,转换都会满足编译器的要求。

您可以改用重载,因为 @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);
  }
}

WORKING DEMO


部分测试用例:

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));