diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 2a5fd2e1a6..b412d5db11 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -59,6 +59,7 @@ import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { isReply } from '@/misc/is-reply.js'; import { trackPromise } from '@/misc/promise-tracker.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -816,7 +817,7 @@ export class NoteCreateService implements OnApplicationShutdown { const mentions = extractMentions(tokens); let mentionedUsers = (await Promise.all(mentions.map(m => this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), - ))).filter(x => x != null) as MiUser[]; + ))).filter(isNotNull); // Drop duplicate users mentionedUsers = mentionedUsers.filter((u, i, self) => diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index d47be79441..0fccc7b950 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit'; import type { MiRemoteUser, MiUser } from '@/models/User.js'; import { concat, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApIds } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { ApObject } from './type.js'; @@ -40,7 +41,7 @@ export class ApAudienceService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))), - )).filter((x): x is MiUser => x != null); + )).filter(isNotNull); if (toGroups.public.length > 0) { return { diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 1cc54b6ff6..8d9cd74a25 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -27,6 +27,7 @@ import { QueueService } from '@/core/QueueService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import type { MiRemoteUser } from '@/models/User.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -521,7 +522,7 @@ export class ApInboxService { const userIds = uris .filter(uri => uri.startsWith(this.config.url + '/users/')) .map(uri => uri.split('/').at(-1)) - .filter((userId): userId is string => userId !== undefined); + .filter(isNotNull); const users = await this.usersRepository.findBy({ id: In(userIds), }); diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 494622909a..d7fb977a99 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -315,7 +315,7 @@ export class ApRendererService { const getPromisedFiles = async (ids: string[]): Promise => { if (ids.length === 0) return []; const items = await this.driveFilesRepository.findBy({ id: In(ids) }); - return ids.map(id => items.find(item => item.id === id)).filter((item): item is MiDriveFile => item != null); + return ids.map(id => items.find(item => item.id === id)).filter(isNotNull); }; let inReplyTo; diff --git a/packages/backend/src/core/activitypub/models/ApMentionService.ts b/packages/backend/src/core/activitypub/models/ApMentionService.ts index 73eea1edf0..0ced7e88af 100644 --- a/packages/backend/src/core/activitypub/models/ApMentionService.ts +++ b/packages/backend/src/core/activitypub/models/ApMentionService.ts @@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit'; import type { MiUser } from '@/models/_.js'; import { toArray, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isMention } from '../type.js'; import { Resolver } from '../ApResolverService.js'; import { ApPersonService } from './ApPersonService.js'; @@ -27,7 +28,7 @@ export class ApMentionService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))), - )).filter((x): x is MiUser => x != null); + )).filter(isNotNull); return mentionedUsers; } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 8da9407216..e201b88173 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -37,6 +37,7 @@ import { ApQuestionService } from './ApQuestionService.js'; import { ApImageService } from './ApImageService.js'; import type { Resolver } from '../ApResolverService.js'; import type { IObject, IPost } from '../type.js'; +import { isNotNull } from '@/misc/is-not-null.js'; @Injectable() export class ApNoteService { @@ -221,7 +222,7 @@ export class ApNoteService { } }; - const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string')); + const uris = unique([note._misskey_quote, note.quoteUrl].filter(isNotNull)); const results = await Promise.all(uris.map(tryResolveNote)); quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index e80cd34a56..744b1ea683 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -38,6 +38,7 @@ import { MetaService } from '@/core/MetaService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { AccountMoveService } from '@/core/AccountMoveService.js'; import { checkHttps } from '@/misc/check-https.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -636,7 +637,7 @@ export class ApPersonService implements OnModuleInit { // とりあえずidを別の時間で生成して順番を維持 let td = 0; - for (const note of featuredNotes.filter((note): note is MiNote => note != null)) { + for (const note of featuredNotes.filter(isNotNull)) { td -= 1000; transactionalEntityManager.insert(MiUserNotePining, { id: this.idService.gen(Date.now() + td), diff --git a/packages/backend/src/core/activitypub/models/ApQuestionService.ts b/packages/backend/src/core/activitypub/models/ApQuestionService.ts index e78b3a3599..d1936cfe1d 100644 --- a/packages/backend/src/core/activitypub/models/ApQuestionService.ts +++ b/packages/backend/src/core/activitypub/models/ApQuestionService.ts @@ -10,6 +10,7 @@ import type { Config } from '@/config.js'; import type { IPoll } from '@/models/Poll.js'; import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isQuestion } from '../type.js'; import { ApLoggerService } from '../ApLoggerService.js'; import { ApResolverService } from '../ApResolverService.js'; @@ -51,7 +52,7 @@ export class ApQuestionService { const choices = question[multiple ? 'anyOf' : 'oneOf'] ?.map((x) => x.name) - .filter((x): x is string => typeof x === 'string') + .filter(isNotNull) ?? []; const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0); diff --git a/packages/backend/src/core/activitypub/models/tag.ts b/packages/backend/src/core/activitypub/models/tag.ts index ced101b764..e7ceec3262 100644 --- a/packages/backend/src/core/activitypub/models/tag.ts +++ b/packages/backend/src/core/activitypub/models/tag.ts @@ -4,6 +4,7 @@ */ import { toArray } from '@/misc/prelude/array.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isHashtag } from '../type.js'; import type { IObject, IApHashtag } from '../type.js'; @@ -15,7 +16,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined): return hashtags.map(tag => { const m = tag.name.match(/^#(.+)/); return m ? m[1] : null; - }).filter((x): x is string => x != null); + }).filter(isNotNull); } export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] { diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index 50f1c49b48..8affe2b3bf 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -259,7 +259,7 @@ export class DriveFileEntityService { options?: PackOptions, ): Promise[]> { const items = await Promise.all(files.map(f => this.packNullable(f, options))); - return items.filter((x): x is Packed<'DriveFile'> => x != null); + return items.filter(isNotNull); } @bindThis diff --git a/packages/backend/src/core/entities/PageEntityService.ts b/packages/backend/src/core/entities/PageEntityService.ts index fe7b137bd2..65c69a49a7 100644 --- a/packages/backend/src/core/entities/PageEntityService.ts +++ b/packages/backend/src/core/entities/PageEntityService.ts @@ -14,6 +14,7 @@ import type { MiPage } from '@/models/Page.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { UserEntityService } from './UserEntityService.js'; import { DriveFileEntityService } from './DriveFileEntityService.js'; @@ -102,7 +103,7 @@ export class PageEntityService { script: page.script, eyeCatchingImageId: page.eyeCatchingImageId, eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null, - attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is MiDriveFile => x != null)), + attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)), likedCount: page.likedCount, isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined, }); diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 53df32f210..14761357a5 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -25,6 +25,7 @@ import { IdService } from '@/core/IdService.js'; import type { AnnouncementService } from '@/core/AnnouncementService.js'; import type { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import type { OnModuleInit } from '@nestjs/common'; import type { NoteEntityService } from './NoteEntityService.js'; import type { DriveFileEntityService } from './DriveFileEntityService.js'; @@ -384,7 +385,7 @@ export class UserEntityService implements OnModuleInit { movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null, alsoKnownAs: user.alsoKnownAs ? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) - .then(xs => xs.length === 0 ? null : xs.filter(x => x != null) as string[]) + .then(xs => xs.length === 0 ? null : xs.filter(isNotNull)) : null, createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, diff --git a/packages/backend/src/misc/is-not-null.ts b/packages/backend/src/misc/is-not-null.ts index 584a09d35a..8d9dc8bb39 100644 --- a/packages/backend/src/misc/is-not-null.ts +++ b/packages/backend/src/misc/is-not-null.ts @@ -3,8 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -// we are using {} as "any non-nullish value" as expected -// eslint-disable-next-line @typescript-eslint/ban-types -export function isNotNull(input: T | undefined | null): input is T { +export function isNotNull>(input: T | undefined | null): input is T { return input != null; } diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index 784ae5088f..b07cdf1ed9 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -12,6 +12,7 @@ import type { MiDriveFile } from '@/models/DriveFile.js'; import { IdService } from '@/core/IdService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -69,7 +70,7 @@ export default class extends Endpoint { // eslint- id: fileId, userId: me.id, }), - ))).filter((file): file is MiDriveFile => file != null); + ))).filter(isNotNull); if (files.length === 0) { throw new Error(); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index 8872b261dd..8bd83ff5ba 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -10,6 +10,7 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js import type { MiDriveFile } from '@/models/DriveFile.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -67,7 +68,7 @@ export default class extends Endpoint { // eslint- id: fileId, userId: me.id, }), - ))).filter((file): file is MiDriveFile => file != null); + ))).filter(isNotNull); if (files.length === 0) { throw new Error(); diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 1f4509764f..784766bcb5 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { MetaService } from '@/core/MetaService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['users'], @@ -52,7 +53,7 @@ export default class extends Endpoint { // eslint- host: acct.host ?? IsNull(), }))); - return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { schema: 'UserDetailed' }); + return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' }); }); } }