Как я могу убедить машинопись в том, что можно вызывать наблюдаемые операторы для субъекта? - PullRequest
0 голосов
/ 17 сентября 2018

Пример кода с использованием 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() - это метод наблюдаемого, а не субъекта, но я понимаю, что субъект также является наблюдаемым, поэтому это не должно быть проблемой. И, на самом деле, если я игнорирую ошибку, код компилируется и работает нормально.

Вещи, которые я пробовал:

  1. Различные способы явного импорта оператора first, например, import 'rxjs/add/operator/first'. Это не меняет ошибку.
  2. Приведение субъекта к наблюдаемой перед вызовом 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() для субъекта?

Чтобы уточнить в ответе на обсуждение типов возврата ниже: у метода также мог быть неправильный тип возврата (должен быть Наблюдаемым, а не Предметом), но это, кажется, отдельная проблема; изменение типа возврата не устраняет ошибку, описанную выше. Еще одна деталь, подтверждающая это, заключается в том, что когда vscode выделяет ошибку, он выделяет только this.response$, а не всю возвращаемую строку, предполагая, что проблема находится между this.response$ и first(), а не между first() и сигнатурой функции:

error highlighted in vscode

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

TL; DR: Более строгие проверки типов, введенные в TypeScript 2.4, несовместимы с RxJS <5.4.2 (<a href="https://github.com/ReactiveX/rxjs/pull/2722" rel="nofollow noreferrer"> из-за ошибки ). Ваша IDE, вероятно, использует TypeScript> = 2.4 для проверки типов. Либо обновите RxJS (рекомендуется), либо понизьте TypeScript, либо используйте программное решение Subject.asObservable вместе с типом возврата Observable<boolean>.

Пояснение:

После обсуждения я изучил исходный код RxJS 5.3.0 и обнаружил, что подписи lift отличаются между Subject и Observable. В частности, мы можем увидеть следующую разницу:

Subject.ts:

lift<R>(operator: Operator<T, R>): Observable<T>

Observable.ts:

lift<R>(operator: Operator<T, R>): Observable<R>

Общий тип возвращаемого наблюдаемого: T в Subject, но R в Observable.

Оператору first() требуется Observable для его контекста this, который не может быть сопоставлен с Subject из-за несовпадающих сигнатур lift. Это очень странно для меня, поскольку Subject расширяет Observable и поэтому должно иметь соответствующие сигнатуры для всех его свойств.

Теперь вот решение: TypeScript ввел более строгие проверки типов с версией 2.4, и RxJS действительно нужно было отследить это изменение, изменив сигнатуру метода lift. Это изменение можно увидеть в журнале изменений в версии 5.4.2 .:

Тема: подпись лифта теперь подходит для более строгих проверок TypeScript 2.4

Вот соответствующий вопрос . Кажется, это была ошибка.

Вы используете 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 для проверки типов.

Alternative

Как упомянуто @cartant, Subject.lift реализован так, чтобы возвращать Subject, но это не может быть выражено с типами TypeScript (нет перегрузки возвращаемого типа, даже если нет уверенности, что есть язык, поддерживающий это).

Итак, еще одно решение - игнорировать проверки типов, приведя к <any>. Таким образом, вы также можете вернуть Subject.

0 голосов
/ 17 сентября 2018

Ваше понимание того, что Субъект также является Наблюдаемым, является правильным, но в той степени, в которой Субъект также может быть использован в качестве Наблюдаемого . Но это не делает 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();
  }
}
...