У меня есть следующий код
let obs$: Observable<string>
obs$.pipe(
tap(data => {
// do stuff
}),
);
Если я использую VSCode и наведу курсор на переменную data
, я вижу, что это тип string
, как и ожидалось.
Тогда я добавить ingnoreElements
после tap
obs$.pipe(
tap(data => {
// do stuff
}),
ignoreElements()
);
Теперь, если я наведу курсор на data
, вывод типа говорит мне, что data
имеет тип any
.
Это кажется как ретроактивный вывод. В чем причина такого поведения вывода типа?
Здесь stackblitz , чтобы воспроизвести эту ситуацию.
ОТВЕТ, предоставленный ответом от @Andrei Gătej
Весь тайна лежит в способе объявления ignoreElements()
, т.е.
export declare function ignoreElements(): OperatorFunction<any, never>;
Теперь вы помещаете ignoreElements()
после оператора, такого как tap()
, который объявлен следующим образом
export declare function tap<T>(observer: PartialObserver<T>): MonoTypeOperatorFunction<T>;
и в основном внутри pipe()
у вас есть такая цепочка, как эта
MonoTypeOperatorFunction<T>,
OperatorFunction<any, never>
, которая pipe()
интерпретируется как: «T» - это общий c тип, «any» - реальный тип , тогда, поскольку ignoreElements () ожидает «any», то «T» должен иметь тип «any»
И это объясняет загадку.
Теперь есть несколько возможных решений. Один из способов - выделить ignoreElements()
в другой pipe()
, например,
obs$.pipe(
tap(data => {
// do stuff
}),
)
.pipe(
ignoreElements()
);
Если вы сделаете это, переменная data
будет выведена с типом string
, что нам и нужно.
Более элегантным решением было бы изменить объявление ignoreElements()
. Если вы объявите это так:
export declare function ignoreElements<T>(): OperatorFunction<T, never>;
, все будет работать, как ожидалось, без необходимости выполнять какие-либо трюки.
Возможно, стоит предложить изменить объявление ignoreElements()
.