Определяемые пользователем функции защиты типа , по крайней мере в настоящее время, строго определены пользователем. Они не определяются автоматически компилятором. Если вы хотите, чтобы возвращаемая функция boolean
работала как защита типа с возвращаемым типом предиката типа, вам необходимо явно пометить ее следующим образом:
const doesNotPropagate = <T>(x: T | undefined) => isNotUndefined(x);
// const doesNotPropagate: <T>(x: T | undefined) => boolean
Функция doesNotPropagate()
ведет себя так же, как isNotUndefined()
во время выполнения, но компилятор больше не видит его как средство защиты типов, поэтому, если вы используете его в качестве фильтра, вы не исключите undefined
в компиляторе.
Существует несколько проблем в GitHub об этом; в настоящее время открытые подписи охраняющего / пропускающего типа отслеживания ошибок: microsoft / TypeScript # 16069 (или, возможно, microsoft / TypeScript # 10734 ). Но, похоже, здесь нет большого движения, так что пока нам нужно просто разобраться с языком таким, какой он есть.
Вот игрушечный пример, с которым можно поиграть различные возможные способы решения этой проблемы, поскольку пример кода в вашем вопросе не представляет собой минимальный воспроизводимый пример , подходящий для перехода в автономную среду IDE. Вы должны иметь возможность адаптировать их к своему собственному коду.
Допустим, у нас есть значение o
типа Observable<string | undefined>
. Тогда это работает:
const a = o.pipe(filter(isNotUndefined)); // Observable<string>
, но это не по причине, указанной выше ... подписи охранника типа не распространяются:
const b = o.pipe(filter(x => isNotUndefined(x))); // Observable<string | undefined>
Мы можем восстановить охрану типа подпись и поведение, если мы вручную аннотируем функцию стрелки следующим образом:
const c = o.pipe(filter((x): x is string => isNotUndefined(x))); // Observable<string>;
Из этого вы можете сделать дополнительную фильтрацию logi c, если хотите:
const d = o.pipe(filter((x): x is string => isNotUndefined(x) && x.length > 3));
// Observable<string>;
Здесь фильтр проверяет что строка определена как и , что ее длина больше 3.
Обратите внимание, что это технически не очень корректный пользовательский тип защиты, так как они имеют тенденцию обрабатывать false
результаты означают, что ввод сужается до исключить защищенный тип:
function badGuard(x: string | undefined): x is string {
return x !== undefined && x.length > 3;
}
const x = Math.random() < 0.5 ? "a" : undefined;
if (!badGuard(x)) {
x; // narrowed to undefined, but could well be string here, oops
}
Здесь, если badGuard(x)
возвращает true
, вы знаете, что x
равно string
, Но если badGuard(x)
возвращает false
, вы не знаете, что x
- это undefined
... но так думает компилятор.
Это правда, что в вашем код, который вы на самом деле не имеете дело с ситуацией, когда фильтр возвращает false
(я полагаю, что последующие параметры канала просто не срабатывают?), так что вам не нужно особо беспокоиться об этом. Тем не менее, может быть лучше выполнить рефакторинг кода в один правильный тип защиты, за которым следует фильтр без защиты типа, который выполняет дополнительные операции логарифмирования c:
const e = o.pipe(filter(isNotUndefined), filter(x => x.length > 3)); // Observable<string>;
Это должно равняться тому же результату при время выполнения, но здесь первый фильтр корректно сужается от Observable<string | undefined>
до Observable<string>
, а второй фильтр сохраняет Observable<string>
(а x
в обратном вызове равен string
) и выполняет дополнительную логику c что фильтры по длине.
И это дает дополнительное преимущество: не требуется аннотации типа, поскольку вы нигде не пытаетесь распространять сигнатуру защиты типа. Так что, вероятно, я рекомендую этот метод.
Хорошо, надеюсь, это поможет; удачи!
Stackblitz ссылка на код