网站搜索

angular - RxJS、TypeScript 以及令人畏惧的“类型不匹配”警告/错误


我知道我漏掉了一些显而易见的东西。下面是实际在生产中可用的伪代码。但是,IDE(IntelliJ IDEA)给了我一个无法解决的错误。可以通过noinspection TypeScriptValidateTypes来抑制,但我真正想知道的是到底发生了什么:

this.authService.onAuthStateChanged()
    .pipe(
        withLatestFrom(
            this.activatedRoute.queryParams.pipe(
                map(params => params['returnUrl'])
            )
        )
    )
    .subscribe(([authState, returnUrl]) => {
        // [...]
    });

我在 subscribe 行收到的错误:

参数类型 ([authState, returnUrl]: readonly [any, any]) => void 不能分配给参数类型 Partial> | undefined

其他相关细节?

// AuthState is just a POJO.
onAuthStateChanged(): BehaviorSubject<AuthState | undefined>

// This is Angular's params object.
// https://angular.io/api/router/Params
export declare type Params = {
    [key: string]: any;
};

我正在使用 RxJS ~7.5.0 和 Typescript ~4.7.4。我也在使用 Angular ^14.2.0,不过这其实并不是一个 Angular 问题。

那么,这里应该发生什么?onAuthStateChanged 会根据用户是否登录发出 AuthState 或 undefined。这会与一个叫做 returnUrl 的查询参数结合,当然它是 string 类型。

现在,这种语法以前的工作方式是可以使用解构赋值语法 ([authState, returnUrl]) 来获取这两个可观察对象——至少我认为它就是这么叫的。正如我所说,它在实际运行中可以正确编译和执行。正如其他人在这里展示的那样,在 StackBlitz 上也不会报错(已更新以更接近我的环境,具有相同的 tslint、angular.json 等)。

然而,我心爱的 IntelliJ…

难道我正在看到 RxJS 最新版本中的一个重大变更吗:

与最新值一起

  • 泛型签名已更改。不要显式传递泛型。

来源:https://rxjs.dev/6-to-7-change-summary#withlatestfrom

这很棒,除了它仍然可以编译和运行。所以,有两件事:

  1. 在幕后发生了什么导致 IntelliJ 出现此错误?
  2. 我怎么才能让它消失?我已经尝试对所有参数进行强类型处理,但无济于事……

答案#1

该问题已在 WEB-57220 跟踪,请关注其更新

在 设置 | 语言与框架 | TypeScript 中启用 TypeScript 语言服务应该有助于消除错误

答案#2

如果你将 onAuthStateChanged 定义为一个返回 BehaviourSubject 的函数,或者直接定义为 BehaviourSubject,你不应该遇到任何错误。

以下代码不会产生任何类型错误

type AuthState = {};

let onAuthStateChanged = new BehaviorSubject<AuthState | undefined>(null);
let onAuthStateChangedFunc: () => BehaviorSubject<AuthState | undefined>;

// This is Angular's params object.
// https://angular.io/api/router/Params
type Params = {
  [key: string]: any;
};

class Foo {
  constructor(private activatedRoute: ActivatedRoute) {}

  foo() {
    onAuthStateChangedFunc() // or
    // onAuthStateChanged
      .pipe(
        withLatestFrom(
          this.activatedRoute.queryParams.pipe(
            map((params) => params['returnUrl'])
          )
        )
      )
      .subscribe(([authState, returnUrl]) => {
        // [...]
      });
  }
}

变量 [authState, returnUrl] 已被正确识别为类型 AuthState 和 any。

请参考这个 Stackblitz