我怎样才能让 typescript 相信可以在 Subject 上调用 Observable 运算符?
How can I convince typescript that it's ok to call Observable operators on a Subject?
示例代码,使用 Angular 4.1.3,rxjs 5.3.0,打字稿 2.2.2:
import { Subject } from 'rxjs'
export class Example {
public response$: Subject<boolean>;
public confirm(prompt: string): Subject<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject<boolean>();
return this.response$.first();
}
}
当我尝试编译这段代码时,typescript 抱怨最后一行:
The 'this' context of type 'Subject<boolean>' is not assignable to method's 'this' of type 'Observable<boolean>'.
Types of property 'lift' are incompatible.
Type '<R>(operator: Operator<boolean, R>) => Observable<boolean>' is not assignable to type '<R>(operator: Operator<boolean, R>) => Observable<R>'.
Type 'Observable<boolean>' is not assignable to type 'Observable<R>'.
Type 'boolean' is not assignable to type 'R'.
我的感觉是说first()
是Observable的方法,不是Subject的方法,但是我的理解是Subject也是Observable,所以这个应该问题不大。而且,事实上,如果我忽略错误代码编译和运行正常。
我尝试过的事情:
- 显式导入
first
运算符的各种方法,例如import 'rxjs/add/operator/first'
。这不会更改错误。
- 在调用
first()
之前将 Subject 转换为 Observable,例如return (this.response$ as Observable<boolean>).first();
。这导致了一个不同但相似的错误,这对我来说也是不正确的:Type 'Observable<boolean>' is not assignable to type 'Subject<boolean>'. Property 'observers' is missing in type 'Observable<boolean>'.
如何让 typescript 相信在 Subject 上调用 first()
是有效的?
为了回应下面对 return 类型的讨论而澄清:该方法可能还有一个不正确的 return 类型(应该是 Observable 而不是 Subject),但这似乎是一个单独的问题;更改 return 类型无法解决上述错误。进一步证实这一点的细节是,当 vscode 突出显示错误时,它只突出显示 this.response$
,而不是整个 return 行,表明问题在 this.response$
和 [= 之间12=],不在 first()
和函数签名之间:
您对 Subject 也是 Observable 的理解是正确的,但在某种程度上 Subject 也可以用作 Observable。但这并不能使 Subject
成为 Observable
,反之亦然。
按照 ggradnig 的建议,您应该将 confirm
函数的 return 类型更改为 Observable<boolean>
而不是 Subject<boolean>
,因为 first
方法在Subject<boolean>
会 return 一个 Observable<boolean>
import { Subject } from 'rxjs'
export class Example {
public response$: Subject < boolean > ;
public confirm(prompt: string): Observable<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject < boolean > ();
return this.response$.first();
}
}
TL;DR: TypeScript 2.4 中引入的更严格的类型检查与 RxJS < 5.4.2 (due to a bug) 不兼容。您的 IDE 可能正在使用 TypeScript >= 2.4 进行类型检查。升级 RxJS(推荐),降级 TypeScript,或者使用编程解决方案 Subject.asObservable
和 return 类型 Observable<boolean>
.
解释:
经过讨论,我查看了 RxJS 5.3.0 源代码,发现 lift
的签名在 Subject
和 Observable
之间有所不同。具体可以看出以下区别:
lift<R>(operator: Operator<T, R>): Observable<T>
lift<R>(operator: Operator<T, R>): Observable<R>
returned Observable 的通用类型在 Subject
中是 T,但在 Observable
。
first()
运算符的 this
上下文需要 Observable
,由于 [=15= 的签名不匹配,Subject
无法匹配].这对我来说很奇怪,因为 Subject
扩展了 Observable
,因此它的所有属性都应该有匹配的签名。
现在是解决方案:TypeScript 在 2.4 版中引入了更严格的类型检查,实际上 RxJS 需要通过更改 lift
方法的签名来跟上这一变化。此更改可以在版本 5.4.2 中看到 in the changelog。:
Subject: lift signature is now appropriate for stricter TypeScript 2.4 checks
Here is the corresponding issue。这似乎是一个错误。
你是 运行 RxJS 5.3,所以这就是你得到错误的原因。
有两种选择。升级 RxJS(推荐)或使用 Subject.asObservable
将类型从 Subject
更改为 Observable
。
正如我在评论中提到的,您函数的 return 类型也需要更改为 Observable<boolean>
。
应用在你的片段上,应该是这样的:
public confirm(prompt: string): Observable<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject<boolean>();
return this.response$.asObservable().first();
}
我看到你的 TypeScript 版本是 2.2,但很可能你的 IDE 使用了另一个 TypeScript 版本来进行类型检查。
备选
如@cartant 所述,Subject.lift
实现为 return a Subject
,但不能用 TypeScript 的类型表示(没有 return 类型重载,甚至不确定是否有支持该语言的语言)。
因此,另一种解决方案是通过强制转换为 <any>
来忽略类型检查。这样你也可以 return Subject
.
示例代码,使用 Angular 4.1.3,rxjs 5.3.0,打字稿 2.2.2:
import { Subject } from 'rxjs'
export class Example {
public response$: Subject<boolean>;
public confirm(prompt: string): Subject<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject<boolean>();
return this.response$.first();
}
}
当我尝试编译这段代码时,typescript 抱怨最后一行:
The 'this' context of type 'Subject<boolean>' is not assignable to method's 'this' of type 'Observable<boolean>'.
Types of property 'lift' are incompatible.
Type '<R>(operator: Operator<boolean, R>) => Observable<boolean>' is not assignable to type '<R>(operator: Operator<boolean, R>) => Observable<R>'.
Type 'Observable<boolean>' is not assignable to type 'Observable<R>'.
Type 'boolean' is not assignable to type 'R'.
我的感觉是说first()
是Observable的方法,不是Subject的方法,但是我的理解是Subject也是Observable,所以这个应该问题不大。而且,事实上,如果我忽略错误代码编译和运行正常。
我尝试过的事情:
- 显式导入
first
运算符的各种方法,例如import 'rxjs/add/operator/first'
。这不会更改错误。 - 在调用
first()
之前将 Subject 转换为 Observable,例如return (this.response$ as Observable<boolean>).first();
。这导致了一个不同但相似的错误,这对我来说也是不正确的:Type 'Observable<boolean>' is not assignable to type 'Subject<boolean>'. Property 'observers' is missing in type 'Observable<boolean>'.
如何让 typescript 相信在 Subject 上调用 first()
是有效的?
为了回应下面对 return 类型的讨论而澄清:该方法可能还有一个不正确的 return 类型(应该是 Observable 而不是 Subject),但这似乎是一个单独的问题;更改 return 类型无法解决上述错误。进一步证实这一点的细节是,当 vscode 突出显示错误时,它只突出显示 this.response$
,而不是整个 return 行,表明问题在 this.response$
和 [= 之间12=],不在 first()
和函数签名之间:
您对 Subject 也是 Observable 的理解是正确的,但在某种程度上 Subject 也可以用作 Observable。但这并不能使 Subject
成为 Observable
,反之亦然。
按照 ggradnig 的建议,您应该将 confirm
函数的 return 类型更改为 Observable<boolean>
而不是 Subject<boolean>
,因为 first
方法在Subject<boolean>
会 return 一个 Observable<boolean>
import { Subject } from 'rxjs'
export class Example {
public response$: Subject < boolean > ;
public confirm(prompt: string): Observable<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject < boolean > ();
return this.response$.first();
}
}
TL;DR: TypeScript 2.4 中引入的更严格的类型检查与 RxJS < 5.4.2 (due to a bug) 不兼容。您的 IDE 可能正在使用 TypeScript >= 2.4 进行类型检查。升级 RxJS(推荐),降级 TypeScript,或者使用编程解决方案 Subject.asObservable
和 return 类型 Observable<boolean>
.
解释:
经过讨论,我查看了 RxJS 5.3.0 源代码,发现 lift
的签名在 Subject
和 Observable
之间有所不同。具体可以看出以下区别:
lift<R>(operator: Operator<T, R>): Observable<T>
lift<R>(operator: Operator<T, R>): Observable<R>
returned Observable 的通用类型在 Subject
中是 T,但在 Observable
。
first()
运算符的 this
上下文需要 Observable
,由于 [=15= 的签名不匹配,Subject
无法匹配].这对我来说很奇怪,因为 Subject
扩展了 Observable
,因此它的所有属性都应该有匹配的签名。
现在是解决方案:TypeScript 在 2.4 版中引入了更严格的类型检查,实际上 RxJS 需要通过更改 lift
方法的签名来跟上这一变化。此更改可以在版本 5.4.2 中看到 in the changelog。:
Subject: lift signature is now appropriate for stricter TypeScript 2.4 checks
Here is the corresponding issue。这似乎是一个错误。
你是 运行 RxJS 5.3,所以这就是你得到错误的原因。
有两种选择。升级 RxJS(推荐)或使用 Subject.asObservable
将类型从 Subject
更改为 Observable
。
正如我在评论中提到的,您函数的 return 类型也需要更改为 Observable<boolean>
。
应用在你的片段上,应该是这样的:
public confirm(prompt: string): Observable<boolean> {
// ...set up a confirmation dialog...
this.response$ = new Subject<boolean>();
return this.response$.asObservable().first();
}
我看到你的 TypeScript 版本是 2.2,但很可能你的 IDE 使用了另一个 TypeScript 版本来进行类型检查。
备选
如@cartant 所述,Subject.lift
实现为 return a Subject
,但不能用 TypeScript 的类型表示(没有 return 类型重载,甚至不确定是否有支持该语言的语言)。
因此,另一种解决方案是通过强制转换为 <any>
来忽略类型检查。这样你也可以 return Subject
.