Я работаю над сервисом аутентификации, который использует объект поведения rxjs для хранения последнего полученного объекта аутентификации и запускает повторную выборку, если срок его действия истек (или еще не был получен).
Мой вопрос касается средства проверки типов TypeScript. Я написал typeguard isNotUndefined
, который утверждает, что именно то, что вы ожидаете.
export function isNotUndefined<T>(input: T | undefined): input is T {
return input !== undefined;
}
Мне уже приходилось писать указанный выше типгард вместо того, чтобы полагаться на auth !== undefined
. Теперь я не могу понять, почему в канале в authGetter$
в приведенном ниже коде тип значения в канале не уменьшается до Auth
после первого фильтра. Вместо этого тип по-прежнему Auth | undefined
, и требуется второй фильтр только с защитой типа, чтобы сузить тип до Auth
.
Итак, в общем, зачем мне нужен второй фильтр, чтобы сузить тип до Auth
? Кроме того, поскольку я пишу код самостоятельно, и никто не проверяет его, я был бы очень признателен, если бы кто-нибудь указал на «запахи кода», которые они распознают (с предложениями о том, что делать вместо этого).
export default class AuthService {
private static lastAuth$ = new BehaviorSubject<Auth | undefined>(undefined);
private static authGetter$ = AuthService.lastAuth$.pipe(
filter(auth => {
if (isNotUndefined(auth) && auth.expiry > new Date()) {
return true ; // identical resulting type with "return isNotUndefined(auth);"
} else {
// retry if auth doesn't exist or is expired
AuthService.authorise().then(newAuth =>
AuthService.lastAuth$.next(newAuth)
);
return false;
}
}),
tap(v => {}), // typechecker says "(parameter) v: Auth | undefined"
filter(isNotUndefined),
tap(v => {}) // typechecker says "(parameter) v: Auth"
);
static getAuth$(): Observable<Auth> {
return this.authGetter$.pipe(first());
}
private static async authorise(): Promise<Auth> {
// auth code goes here (irrelevant for this question)...
// typecast dummy return to make typechecker happy
return Promise.resolve(<Auth>{});
}
}
Я прилагаю фотографию моего кода с красивой подсветкой синтаксиса для вашего удобства и удовольствия :)
lastAuth$
определяется как<Auth | undefined>
, поскольку это то, что вы в конечном итоге возвращаете изAuthService.lastAuth$.pipe(filter(...))
. - person Andrew Nolan   schedule 23.04.2020new BehaviorSubject<Auth | undefined>
. Ваш тип охраняет меня, нужно поместить куда-нибудь еще, где нужно проверить, есть лиAuth
или, возможно, попробовать.map
вместо.filter
для создания типаAuth
- person Andrew Nolan   schedule 23.04.2020<Auth | undefined>
. Это не имеет смысла, потому что вы все равно можете вызывать.next()
сnull
илиundefined
, даже если он определен только как<Auth>
. Это наверняка приведет к проблемам с типом в вашем конвейере, потому что вы не сможете утверждать, что ваше значение не является неопределенным, если вы явно не определите тип с помощьюtap((a: Auth) => ..)
. Но вы действительно не должны делать это в вашем случае. - person Reqven   schedule 23.04.2020