From e4b6972c051fbb69c4221b34c54ad4b02f979654 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 6 Jan 2025 17:40:07 -0600 Subject: [PATCH] Add fastIsType util --- src/state/queries/notifications/util.ts | 18 +++++++++++------- src/state/queries/post-thread.ts | 6 +++++- src/types/atproto/index.ts | 23 +++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index e5f957ec2b..0ffa7302dc 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -14,6 +14,7 @@ import {QueryClient} from '@tanstack/react-query' import chunk from 'lodash.chunk' import {labelIsHideableOffense} from '#/lib/moderation' +import * as atp from '#/types/atproto' import {precacheProfile} from '../profile' import {FeedNotification, FeedPage, NotificationType} from './types' @@ -255,14 +256,17 @@ function getSubjectUri( return notif.uri } else if (type === 'post-like' || type === 'repost') { if ( - AppBskyFeedRepost.isRecord(notif.record) || - AppBskyFeedLike.isRecord(notif.record) + atp.fastIsType( + notif.record, + AppBskyFeedRepost.isRecord, + ) || + atp.fastIsType( + notif.record, + AppBskyFeedLike.isRecord, + ) ) { - const record = notif.record as - | AppBskyFeedRepost.Record - | AppBskyFeedLike.Record - return typeof record.subject?.uri === 'string' - ? record.subject?.uri + return typeof notif.record.subject?.uri === 'string' + ? notif.record.subject?.uri : undefined } } else if (type === 'feedgen-like') { diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts index 5427268420..beb50752d0 100644 --- a/src/state/queries/post-thread.ts +++ b/src/state/queries/post-thread.ts @@ -18,6 +18,7 @@ import { findAllProfilesInQueryData as findAllProfilesInSearchQueryData, } from '#/state/queries/search-posts' import {useAgent} from '#/state/session' +import * as atp from '#/types/atproto' import { findAllPostsInQueryData as findAllPostsInNotifsQueryData, findAllProfilesInQueryData as findAllProfilesInNotifsQueryData, @@ -329,7 +330,10 @@ function responseToThreadNodes( ): ThreadNode { if ( AppBskyFeedDefs.isThreadViewPost(node) && - AppBskyFeedPost.isValidRecord(node.post.record) + atp.fastIsType( + node.post.record, + AppBskyFeedPost.isRecord, + ) ) { const post = node.post // These should normally be present. They're missing only for diff --git a/src/types/atproto/index.ts b/src/types/atproto/index.ts index 58e2a5eb23..0f17653cc7 100644 --- a/src/types/atproto/index.ts +++ b/src/types/atproto/index.ts @@ -1 +1,24 @@ export * as profile from '#/types/atproto/profile' + +/** + * Use sparingly, and only when you know it's safe to do so. + * + * Our SDK's `is*` identity utils do not assert the type of the entire object, + * and although the `isValid*` utils do, they also fully validate the object + * shape, which has a performance cost. This util allows us to prescribe the + * type we expect, while only checking the `$type` value of the record. + * + * Usage: + * ```ts + * import * as atp from '#/types/atproto' + * + * if (atp.fastIsType(node.post.record, AppBskyFeedPost.isRecord)) { + * } + * ``` + */ +export function fastIsType( + record: unknown, + identity: (v: V) => boolean, +): record is R { + return identity(record) +}