From b013649a41be585423cfa182e8e2a300c7dcf410 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sun, 9 Nov 2025 00:51:34 -0500 Subject: [PATCH] prefer type-only imports in testing utilities --- .../src/global/CacheManagementService.ts | 4 ++-- .../src/global/InternalEventService.ts | 23 ++++++++++--------- packages/backend/src/global/TimeService.ts | 2 +- packages/backend/src/misc/cache.ts | 4 ++-- .../test/misc/FakeCacheManagementService.ts | 2 +- packages/backend/test/misc/FakeRedis.ts | 13 ++++++----- .../backend/test/misc/GodOfTimeService.ts | 2 +- packages/backend/test/misc/MockRedis.ts | 2 +- 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/packages/backend/src/global/CacheManagementService.ts b/packages/backend/src/global/CacheManagementService.ts index 8101ad78bc..30e74211fd 100644 --- a/packages/backend/src/global/CacheManagementService.ts +++ b/packages/backend/src/global/CacheManagementService.ts @@ -3,8 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; -import * as Redis from 'ioredis'; +import { Inject, Injectable, type OnApplicationShutdown } from '@nestjs/common'; import { MemoryKVCache, MemorySingleCache, @@ -26,6 +25,7 @@ import { DI } from '@/di-symbols.js'; import { TimeService, type TimerHandle } from '@/global/TimeService.js'; import { InternalEventService } from '@/global/InternalEventService.js'; import { callAllOn } from '@/misc/call-all.js'; +import type * as Redis from 'ioredis'; // This is the one place that's *supposed* to new() up caches. /* eslint-disable no-restricted-syntax */ diff --git a/packages/backend/src/global/InternalEventService.ts b/packages/backend/src/global/InternalEventService.ts index be685e6b48..f2af08b036 100644 --- a/packages/backend/src/global/InternalEventService.ts +++ b/packages/backend/src/global/InternalEventService.ts @@ -4,13 +4,14 @@ */ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; -import Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; import type { GlobalEvents, InternalEventTypes } from '@/core/GlobalEventService.js'; import type { Config } from '@/config.js'; -import { bindThis } from '@/decorators.js'; +import type Redis from 'ioredis'; -export type Listener = (value: InternalEventTypes[K], key: K, isLocal: boolean) => void | Promise; +export type EventTypes = InternalEventTypes; +export type Listener = (value: EventTypes[K], key: K, isLocal: boolean) => void | Promise; export interface ListenerProps { ignoreLocal?: boolean, @@ -19,7 +20,7 @@ export interface ListenerProps { @Injectable() export class InternalEventService implements OnApplicationShutdown { - private readonly listeners = new Map, ListenerProps>>(); + private readonly listeners = new Map, ListenerProps>>(); constructor( @Inject(DI.redisForSub) @@ -35,7 +36,7 @@ export class InternalEventService implements OnApplicationShutdown { } @bindThis - public on(type: K, listener: Listener, props?: ListenerProps): void { + public on(type: K, listener: Listener, props?: ListenerProps): void { let set = this.listeners.get(type); if (!set) { set = new Map(); @@ -43,16 +44,16 @@ export class InternalEventService implements OnApplicationShutdown { } // Functionally, this is just a set with metadata on the values. - set.set(listener as Listener, props ?? {}); + set.set(listener as Listener, props ?? {}); } @bindThis - public off(type: K, listener: Listener): void { - this.listeners.get(type)?.delete(listener as Listener); + public off(type: K, listener: Listener): void { + this.listeners.get(type)?.delete(listener as Listener); } @bindThis - public async emit(type: K, value: InternalEventTypes[K]): Promise { + public async emit(type: K, value: EventTypes[K]): Promise { await this.emitInternal(type, value, true); await this.redisForPub.publish(this.config.host, JSON.stringify({ channel: 'internal', @@ -61,7 +62,7 @@ export class InternalEventService implements OnApplicationShutdown { } @bindThis - private async emitInternal(type: K, value: InternalEventTypes[K], isLocal: boolean): Promise { + private async emitInternal(type: K, value: EventTypes[K], isLocal: boolean): Promise { const listeners = this.listeners.get(type); if (!listeners) { return; @@ -84,7 +85,7 @@ export class InternalEventService implements OnApplicationShutdown { if (obj.channel === 'internal') { const { type, body } = obj.message as GlobalEvents['internal']['payload']; if (!isLocalInternalEvent(body) || body._pid !== process.pid) { - await this.emitInternal(type, body as InternalEventTypes[keyof InternalEventTypes], false); + await this.emitInternal(type, body as EventTypes[keyof EventTypes], false); } } } diff --git a/packages/backend/src/global/TimeService.ts b/packages/backend/src/global/TimeService.ts index c2fdb9d76e..035489f6f8 100644 --- a/packages/backend/src/global/TimeService.ts +++ b/packages/backend/src/global/TimeService.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Injectable, OnApplicationShutdown } from '@nestjs/common'; +import { Injectable, type OnApplicationShutdown } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; const timerTokenSymbol = Symbol('timerToken'); diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index b6bbbcd067..a5b36d923f 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as Redis from 'ioredis'; +import type * as Redis from 'ioredis'; import { bindThis } from '@/decorators.js'; -import { TimeService } from '@/global/TimeService.js'; +import type { TimeService } from '@/global/TimeService.js'; export interface RedisCacheServices extends MemoryCacheServices { readonly redisClient: Redis.Redis diff --git a/packages/backend/test/misc/FakeCacheManagementService.ts b/packages/backend/test/misc/FakeCacheManagementService.ts index 5583b7e8e7..bd6c8aa8ef 100644 --- a/packages/backend/test/misc/FakeCacheManagementService.ts +++ b/packages/backend/test/misc/FakeCacheManagementService.ts @@ -3,11 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as Redis from 'ioredis'; import { Injectable } from '@nestjs/common'; import { GodOfTimeService } from './GodOfTimeService.js'; import { MockInternalEventService } from './MockInternalEventService.js'; import { MockRedis } from './MockRedis.js'; +import type * as Redis from 'ioredis'; import type { QuantumKVOpts } from '@/misc/QuantumKVCache.js'; import type { RedisKVCacheOpts, RedisSingleCacheOpts, MemoryCacheOpts } from '@/misc/cache.js'; import type { TimeService } from '@/global/TimeService.js'; diff --git a/packages/backend/test/misc/FakeRedis.ts b/packages/backend/test/misc/FakeRedis.ts index c9384490fe..e26962760f 100644 --- a/packages/backend/test/misc/FakeRedis.ts +++ b/packages/backend/test/misc/FakeRedis.ts @@ -3,7 +3,8 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as Redis from 'ioredis'; +import { Redis as RedisConstructor } from 'ioredis'; +import type * as Redis from 'ioredis'; export type RedisKey = Redis.RedisKey; export type RedisString = Buffer | string; @@ -14,7 +15,7 @@ export type RedisCallback = Redis.Callback; export type Ok = 'OK'; export const ok = 'OK' as const; -export type FakeRedis = Redis.Redis; +export type FakeRedis = RedisConstructor; export interface FakeRedisConstructor { new (): FakeRedis; } @@ -25,7 +26,7 @@ export interface FakeRedisConstructor { export const FakeRedis: FakeRedisConstructor = createFakeRedis(); function createFakeRedis(): FakeRedisConstructor { - class FakeRedis implements Partial { + class FakeRedis implements Partial { async connect(callback?: RedisCallback): Promise { // no-op callback?.(null); @@ -71,8 +72,8 @@ function createFakeRedis(): FakeRedisConstructor { } } - const fakeProto = FakeRedis.prototype as Partial; - const redisProto = Redis.Redis.prototype as Partial; + const fakeProto = FakeRedis.prototype as Partial; + const redisProto = RedisConstructor.prototype as Partial; // Override all methods and accessors from Redis for (const [key, property] of allProps(redisProto)) { @@ -102,7 +103,7 @@ function createFakeRedis(): FakeRedisConstructor { // test const test = new FakeRedis(); - if (!(test instanceof Redis.Redis)) { + if (!(test instanceof RedisConstructor)) { throw new Error('failed to extend'); } diff --git a/packages/backend/test/misc/GodOfTimeService.ts b/packages/backend/test/misc/GodOfTimeService.ts index 40133509d5..61e267a52d 100644 --- a/packages/backend/test/misc/GodOfTimeService.ts +++ b/packages/backend/test/misc/GodOfTimeService.ts @@ -4,7 +4,7 @@ */ import { Injectable } from '@nestjs/common'; -import { TimeService, Timer } from '@/global/TimeService.js'; +import { TimeService, type Timer } from '@/global/TimeService.js'; import { addPatch, type DatePatch } from '@/misc/patch-date.js'; /** diff --git a/packages/backend/test/misc/MockRedis.ts b/packages/backend/test/misc/MockRedis.ts index 6e0796da3c..b706a40f6d 100644 --- a/packages/backend/test/misc/MockRedis.ts +++ b/packages/backend/test/misc/MockRedis.ts @@ -7,7 +7,7 @@ import { Injectable } from '@nestjs/common'; import { FakeRedis, ok, type RedisString } from './FakeRedis.js'; import type { RedisKey, RedisNumber, RedisValue, RedisCallback, Ok } from './FakeRedis.js'; import type { ChainableCommander } from 'ioredis'; -import { TimeService, NativeTimeService } from '@/global/TimeService.js'; +import { NativeTimeService, type TimeService } from '@/global/TimeService.js'; import { bindThis } from '@/decorators.js'; export interface MockRedisConstructor {