示例代码,使用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();
}
}
当我尝试编译此代码时,打字稿抱怨最后一行:
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()
之前将主体投射为可观察对象,例如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>'.
如何使打字稿确信对主题调用first()
是有效的?
为响应下面对返回类型的讨论而澄清:该方法可能还具有不正确的返回类型(应为Observable而不是Subject),但这似乎是一个单独的问题;更改返回类型不能解决上述错误。进一步确认这一点的细节是,当vscode突出显示错误时,它仅突出显示this.response$
,而不突出整个返回行,这表明问题出在this.response$
和first()
之间,而不是{{ 1}}和函数的签名:
答案 0 :(得分:3)
您对主体也是可观察对象的理解是正确的,但是在一定程度上,主题也可以用作可观察对象。但这并不能使Subject
变成Observable
,反之亦然。
如ggradnig所建议,您应该将confirm
函数的返回类型更改为Observable<boolean>
而不是Subject<boolean>
,因为first
上的Subject<boolean>
方法会返回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();
}
}
答案 1 :(得分:1)
TL; DR::TypeScript 2.4中引入的更严格的类型检查与RxJS <5.4.2(due to a bug)不兼容。您的IDE可能正在使用TypeScript> = 2.4进行类型检查。升级RxJS(推荐),降级TypeScript或将编程解决方案Subject.asObservable
与返回类型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>
返回的Observable的通用类型在Subject
中是 T ,但是在Observable
中是 R 。
first()
运算符的Observable
上下文需要一个this
,由于Subject
的签名不匹配,因此lift
无法匹配。这对我来说很奇怪,因为Subject
扩展了Observable
,因此,其所有属性都应具有匹配的签名。
现在是解决方案:TypeScript在版本2.4中引入了更严格的类型检查,实际上RxJS需要通过更改lift
方法的签名来赶上这一更改。可以在版本{strong> 5.4.2 的in the changelog上看到此更改。
主题:提升签名现在适用于更严格的TypeScript 2.4检查
Here is the corresponding issue。看来是个错误。
您正在运行RxJS 5.3 ,因此这就是您收到错误的原因。
有两个选项。升级RxJS(推荐)或使用Subject.asObservable
将类型从Subject
更改为Observable
。
如我的评论中所述,函数的返回类型也需要更改为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
的实现是为了返回Subject
,但这不能用TypeScript的类型表示(没有返回类型重载,甚至不能确定是否有一种语言可以支持)。
因此,另一种解决方案是通过强制转换为<any>
来忽略类型检查。这样,您还可以返回Subject
。