Typescript 确保函数中只能使用同步管道(不允许使用异步管道)

Typescript 确保函数中只能使用同步管道(不允许使用异步管道),typescript,rxjs,Typescript,Rxjs,我正在开发一个Angular应用程序,其中数据必须以同步方式从各种源(带有映射管道函数的行为子对象)获取 到目前为止,一直是这样做的: let magicNumber; this.magicService.magicNumber$.pipe(take(1)).subscribe(val => magicNumber = val)); export function select<T>(inStream: Observable<T>): T { let valu

我正在开发一个Angular应用程序,其中数据必须以同步方式从各种源(带有映射管道函数的行为子对象)获取

到目前为止,一直是这样做的:

let magicNumber;
this.magicService.magicNumber$.pipe(take(1)).subscribe(val => magicNumber = val));
export function select<T>(inStream: Observable<T>): T {
  let value: T;

  race(
    inStream,
    throwError(
      new Error(
        select.name +
          " expects a synchronous stream. Received an asynchronous stream."
      )
    )
  )
    .pipe(take(1))
    .subscribe(val => (value = val));

  return value;
}
function purchase() {
  const userName = select(this.userService.userName$);
  const basketContent = select(this.basketService.basketContent$);
  this.http.post("http://niceUrl.com", {
    userName,
    basketContent
  }).subscribe(
    ReduceResponse
  )
等等。这最终成为一堆样板,所以我想做一个函数来显著减少这个样板。然而,我正在编写的函数只用于同步操作,但它接受任何类型的可观察操作。目前,我正试图通过在将具有异步性的流传递给函数时抛出一个错误来实现这一点,当前的实现如下所示:

let magicNumber;
this.magicService.magicNumber$.pipe(take(1)).subscribe(val => magicNumber = val));
export function select<T>(inStream: Observable<T>): T {
  let value: T;

  race(
    inStream,
    throwError(
      new Error(
        select.name +
          " expects a synchronous stream. Received an asynchronous stream."
      )
    )
  )
    .pipe(take(1))
    .subscribe(val => (value = val));

  return value;
}
function purchase() {
  const userName = select(this.userService.userName$);
  const basketContent = select(this.basketService.basketContent$);
  this.http.post("http://niceUrl.com", {
    userName,
    basketContent
  }).subscribe(
    ReduceResponse
  )
然而,有没有更优雅的方法来实施这一点?更可取的是,我有一些类型脚本技巧,允许我告诉开发人员他们在开发过程中发送了错误类型的管道作为参数,但我不确定是否有任何方法可以仅从类型推断识别同步管道和异步管道

现在的问题是,开发人员在运行代码之前不会注意到他们做错了什么,而代码由于被传递到异步流而崩溃

例如,假设我有三个服务,
userService
basketService
purchaseService

userService
中,我有以下内容:

userData$: BehaviorSubject<UserDataStore>;
...
userName$ = userData$.pipe(
  map(({ userName }) => userName));
(本例中简化了管道;实际上,它们确实包含重试代码和错误捕获等。)

换句话说,我所说的是从已经存储在BehaviorSubject中的服务中收集数据的过程,我知道收集将是同步的,并对此进行了简要说明

我知道这段代码只有在流是同步的情况下才能工作,所以我想阻止其他程序员尝试将异步流传递到方法中

用于比较;在实施
select
方法之前,这是上面的示例:

function purchase() {
  let userName, basketContent;
  this.userService.userName$.pipe(take(1)).subscribe(val => userName = val);
  this.basketService.basketContent$.pipe(take(1)).subscribe(val => basketContent = val);
  this.http.post("http://niceUrl.com", {
    userName,
    basketContent
  }).subscribe(
    ReduceResponse
  )

PS!我们已经在使用OnPush-in组件代码实践严格的异步数据更新,因此关于在组件中异步使用RxJs的注释是没有必要的

我不是在谈论http调用本身。这些是已收集数据的前端中运行的其他服务的订阅。默认情况下,从BehaviorSubjects路由的RxJs管道是同步的,为此,我想创建一个简单的选择函数来简化样板文件。我只是希望其他开发人员要小心,不要相信他们可以在同步代码中对异步管道使用此函数。那么HTTP从何而来呢?您在第一句中直接提到了它,因此它似乎很重要,来自浏览器的HTTP调用必须是异步的,以避免我提到的阻塞行为。你能澄清一下吗?我用一个更具体的例子更新了这个问题。HTTP作为一个示例被提及,只是为了说明函数被调用,并且在执行异步操作之前将使用同步代码进行准备。因此,问题的实质是对已经同步的代码进行简化,但要确保它不是以异步方式使用的,但实际上根本不需要这样做。forkJoin两个服务观察值,然后从结果值数组中平面映射请求。@T.J.Crowder你说得对。HTTP部分是不相关的。我想我应该包括它,以避免人们告诉我正确的方法(在组件代码中,仅使用异步流),我们已经在这样做了