diff --git a/keyserver/src/creators/update-creator.js b/keyserver/src/creators/update-creator.js
--- a/keyserver/src/creators/update-creator.js
+++ b/keyserver/src/creators/update-creator.js
@@ -26,7 +26,7 @@
   redisMessageTypes,
   type NewUpdatesRedisMessage,
 } from 'lib/types/redis-types.js';
-import type { RawThreadInfo } from 'lib/types/thread-types.js';
+import type { RawThreadInfos } from 'lib/types/thread-types';
 import {
   type ServerUpdateInfo,
   type UpdateData,
@@ -84,7 +84,7 @@
       viewer: Viewer,
       calendarQuery: ?CalendarQuery,
       updatesForCurrentSession?: UpdatesForCurrentSession,
-      threadInfos: { +[id: string]: RawThreadInfo },
+      threadInfos: RawThreadInfos,
     };
 const defaultUpdateCreationResult = { viewerUpdates: [], userInfos: {} };
 const sortFunction = (
diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -32,7 +32,7 @@
   SubscriptionUpdateRequest,
   SubscriptionUpdateResult,
 } from '../types/subscription-types.js';
-import type { RawThreadInfo } from '../types/thread-types';
+import type { RawThreadInfos } from '../types/thread-types';
 import type {
   UserInfo,
   PasswordUpdate,
@@ -245,7 +245,7 @@
 
     const userInfosArrays = [];
 
-    let threadInfos: { +[id: string]: RawThreadInfo } = {};
+    let threadInfos: RawThreadInfos = {};
     const calendarResult = {
       calendarQuery: logInInfo.calendarQuery,
       rawEntryInfos: [],
diff --git a/lib/ops/thread-store-ops.js b/lib/ops/thread-store-ops.js
--- a/lib/ops/thread-store-ops.js
+++ b/lib/ops/thread-store-ops.js
@@ -4,6 +4,7 @@
 import type {
   ClientDBThreadInfo,
   RawThreadInfo,
+  RawThreadInfos,
   ThreadStore,
 } from '../types/thread-types.js';
 import {
@@ -44,7 +45,7 @@
   ThreadStore,
   ThreadStoreOperation,
   ClientDBThreadStoreOperation,
-  { +[id: string]: RawThreadInfo },
+  RawThreadInfos,
   ClientDBThreadInfo,
 > = {
   processStoreOperations(
diff --git a/lib/reducers/calendar-filters-reducer.js b/lib/reducers/calendar-filters-reducer.js
--- a/lib/reducers/calendar-filters-reducer.js
+++ b/lib/reducers/calendar-filters-reducer.js
@@ -37,7 +37,7 @@
   fullStateSyncActionType,
   incrementalStateSyncActionType,
 } from '../types/socket-types.js';
-import type { RawThreadInfo, ThreadStore } from '../types/thread-types.js';
+import type { RawThreadInfos, ThreadStore } from '../types/thread-types.js';
 import {
   type ClientUpdateInfo,
   processUpdatesActionType,
@@ -158,7 +158,7 @@
 
 function removeDeletedThreadIDsFromFilterList(
   state: $ReadOnlyArray<CalendarFilter>,
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): $ReadOnlyArray<CalendarFilter> {
   const currentlyFilteredIDs = filteredThreadIDs(state);
   if (!currentlyFilteredIDs) {
diff --git a/lib/reducers/entry-reducer.js b/lib/reducers/entry-reducer.js
--- a/lib/reducers/entry-reducer.js
+++ b/lib/reducers/entry-reducer.js
@@ -54,7 +54,7 @@
   fullStateSyncActionType,
   incrementalStateSyncActionType,
 } from '../types/socket-types.js';
-import { type RawThreadInfo } from '../types/thread-types.js';
+import { type RawThreadInfos } from '../types/thread-types.js';
 import {
   type ClientUpdateInfo,
   processUpdatesActionType,
@@ -90,7 +90,7 @@
   currentEntryInfos: { +[id: string]: RawEntryInfo },
   currentDaysToEntries: ?{ +[day: string]: string[] },
   newEntryInfos: $ReadOnlyArray<RawEntryInfo>,
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ) {
   const mergedEntryInfos = {};
   let someEntryUpdated = false;
@@ -163,7 +163,7 @@
 function reduceEntryInfos(
   entryStore: EntryStore,
   action: BaseAction,
-  newThreadInfos: { +[id: string]: RawThreadInfo },
+  newThreadInfos: RawThreadInfos,
 ): [EntryStore, $ReadOnlyArray<ClientEntryInconsistencyReportCreationRequest>] {
   const { entryInfos, daysToEntries, lastUserInteractionCalendar } = entryStore;
   if (
diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js
--- a/lib/reducers/message-reducer.js
+++ b/lib/reducers/message-reducer.js
@@ -93,7 +93,7 @@
   incrementalStateSyncActionType,
 } from '../types/socket-types.js';
 import { threadPermissions } from '../types/thread-permission-types.js';
-import { type RawThreadInfo } from '../types/thread-types.js';
+import type { RawThreadInfo, RawThreadInfos } from '../types/thread-types.js';
 import {
   type ClientUpdateInfo,
   processUpdatesActionType,
@@ -146,7 +146,7 @@
   messageInfos: $ReadOnlyArray<RawMessageInfo>,
   truncationStatus: { [threadID: string]: MessageTruncationStatus },
   currentAsOf: number,
-  threadInfos: { +[threadID: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): FreshMessageStoreResult {
   const unshimmed = unshimMessageInfos(messageInfos);
   const orderedMessageInfos = sortMessageInfoList(unshimmed);
@@ -212,7 +212,7 @@
 
 function reassignMessagesToRealizedThreads(
   messageStore: MessageStore,
-  threadInfos: { +[threadID: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): ReassignmentResult {
   const pendingToRealizedThreadIDs =
     pendingToRealizedThreadIDsSelector(threadInfos);
@@ -305,7 +305,7 @@
   oldMessageStore: MessageStore,
   newMessageInfos: $ReadOnlyArray<RawMessageInfo>,
   truncationStatus: { [threadID: string]: MessageTruncationStatus },
-  threadInfos: { +[threadID: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): MergeNewMessagesResult {
   const {
     messageStoreOperations: updateWithLatestThreadInfosOps,
@@ -623,7 +623,7 @@
 };
 function updateMessageStoreWithLatestThreadInfos(
   messageStore: MessageStore,
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): UpdateMessageStoreWithLatestThreadInfosResult {
   const messageStoreOperations: MessageStoreOperation[] = [];
   const {
@@ -691,7 +691,7 @@
 
 function ensureRealizedThreadIDIsUsedWhenPossible<T: RawMessageInfo>(
   payload: T,
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): T {
   const pendingToRealizedThreadIDs =
     pendingToRealizedThreadIDsSelector(threadInfos);
@@ -711,7 +711,7 @@
 function reduceMessageStore(
   messageStore: MessageStore,
   action: BaseAction,
-  newThreadInfos: { +[id: string]: RawThreadInfo },
+  newThreadInfos: RawThreadInfos,
 ): ReduceMessageStoreResult {
   if (
     action.type === logInActionTypes.success ||
diff --git a/lib/reducers/thread-reducer.js b/lib/reducers/thread-reducer.js
--- a/lib/reducers/thread-reducer.js
+++ b/lib/reducers/thread-reducer.js
@@ -41,7 +41,7 @@
   fullStateSyncActionType,
   incrementalStateSyncActionType,
 } from '../types/socket-types.js';
-import type { RawThreadInfo, ThreadStore } from '../types/thread-types.js';
+import type { RawThreadInfos, ThreadStore } from '../types/thread-types.js';
 import {
   type ClientUpdateInfo,
   processUpdatesActionType,
@@ -52,7 +52,7 @@
   threadStoreOpsHandlers;
 
 function generateOpsForThreadUpdates(
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
   payload: {
     +updatesResult: { +newUpdates: $ReadOnlyArray<ClientUpdateInfo>, ... },
     ...
diff --git a/lib/selectors/thread-selectors.js b/lib/selectors/thread-selectors.js
--- a/lib/selectors/thread-selectors.js
+++ b/lib/selectors/thread-selectors.js
@@ -51,6 +51,7 @@
   type RawThreadInfo,
   type RelativeMemberInfo,
   type SidebarInfo,
+  type RawThreadInfos,
 } from '../types/thread-types.js';
 import { dateString, dateFromString } from '../utils/date-utils.js';
 import { values } from '../utils/objects.js';
@@ -273,7 +274,7 @@
 
 const unreadCount: (state: BaseAppState<>) => number = createSelector(
   (state: BaseAppState<>) => state.threadStore.threadInfos,
-  (threadInfos: { +[id: string]: RawThreadInfo }): number =>
+  (threadInfos: RawThreadInfos): number =>
     values(threadInfos).filter(
       threadInfo =>
         threadInHomeChatList(threadInfo) && threadInfo.currentUser.unread,
@@ -282,7 +283,7 @@
 
 const unreadBackgroundCount: (state: BaseAppState<>) => number = createSelector(
   (state: BaseAppState<>) => state.threadStore.threadInfos,
-  (threadInfos: { +[id: string]: RawThreadInfo }): number =>
+  (threadInfos: RawThreadInfos): number =>
     values(threadInfos).filter(
       threadInfo =>
         threadInBackgroundChatList(threadInfo) && threadInfo.currentUser.unread,
@@ -351,7 +352,7 @@
 
 function mostRecentlyReadThread(
   messageStore: MessageStore,
-  threadInfos: { +[id: string]: RawThreadInfo },
+  threadInfos: RawThreadInfos,
 ): ?string {
   let mostRecent = null;
   for (const threadID in threadInfos) {
@@ -393,7 +394,7 @@
   (state: BaseAppState<>) => state.threadStore.threadInfos,
   threadInfoSelector,
   (
-    rawThreadInfos: { +[id: string]: RawThreadInfo },
+    rawThreadInfos: RawThreadInfos,
     threadInfos: { +[id: string]: ThreadInfo },
   ) => {
     const pendingToRealizedThreadIDs =
@@ -408,11 +409,11 @@
     return result;
   },
 );
-const pendingToRealizedThreadIDsSelector: (rawThreadInfos: {
-  +[id: string]: RawThreadInfo,
-}) => $ReadOnlyMap<string, string> = createSelector(
-  (rawThreadInfos: { +[id: string]: RawThreadInfo }) => rawThreadInfos,
-  (rawThreadInfos: { +[id: string]: RawThreadInfo }) => {
+const pendingToRealizedThreadIDsSelector: (
+  rawThreadInfos: RawThreadInfos,
+) => $ReadOnlyMap<string, string> = createSelector(
+  (rawThreadInfos: RawThreadInfos) => rawThreadInfos,
+  (rawThreadInfos: RawThreadInfos) => {
     const result = new Map();
     for (const threadID in rawThreadInfos) {
       const rawThreadInfo = rawThreadInfos[threadID];
diff --git a/lib/types/account-types.js b/lib/types/account-types.js
--- a/lib/types/account-types.js
+++ b/lib/types/account-types.js
@@ -15,7 +15,7 @@
   type GenericMessagesResult,
 } from './message-types.js';
 import type { PreRequestUserState } from './session-types.js';
-import { type RawThreadInfo } from './thread-types.js';
+import { type RawThreadInfos } from './thread-types.js';
 import {
   type UserInfo,
   type LoggedOutUserInfo,
@@ -69,7 +69,7 @@
   rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
   currentUserInfo: LoggedInUserInfo,
   cookieChange: {
-    threadInfos: { +[id: string]: RawThreadInfo },
+    threadInfos: RawThreadInfos,
     userInfos: $ReadOnlyArray<UserInfo>,
   },
 };
@@ -77,7 +77,7 @@
 export type RegisterResult = {
   +currentUserInfo: LoggedInUserInfo,
   +rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
-  +threadInfos: { +[id: string]: RawThreadInfo },
+  +threadInfos: RawThreadInfos,
   +userInfos: $ReadOnlyArray<UserInfo>,
   +calendarQuery: CalendarQuery,
 };
@@ -142,14 +142,14 @@
   +rawEntryInfos?: ?$ReadOnlyArray<RawEntryInfo>,
   +serverTime: number,
   +cookieChange: {
-    +threadInfos: { +[id: string]: RawThreadInfo },
+    +threadInfos: RawThreadInfos,
     +userInfos: $ReadOnlyArray<UserInfo>,
   },
   +notAcknowledgedPolicies?: $ReadOnlyArray<PolicyType>,
 };
 
 export type LogInResult = {
-  +threadInfos: { +[id: string]: RawThreadInfo },
+  +threadInfos: RawThreadInfos,
   +currentUserInfo: LoggedInUserInfo,
   +messagesResult: GenericMessagesResult,
   +userInfos: $ReadOnlyArray<UserInfo>,
diff --git a/lib/types/report-types.js b/lib/types/report-types.js
--- a/lib/types/report-types.js
+++ b/lib/types/report-types.js
@@ -7,7 +7,7 @@
 import { type RawEntryInfo, type CalendarQuery } from './entry-types.js';
 import { type MediaMission } from './media-types.js';
 import type { AppState, BaseAction } from './redux-types.js';
-import { type RawThreadInfo } from './thread-types.js';
+import { type RawThreadInfos } from './thread-types.js';
 import type { UserInfo, UserInfos } from './user-types.js';
 import { tPlatformDetails, tShape } from '../utils/validation-utils.js';
 
@@ -71,10 +71,10 @@
 };
 export type ThreadInconsistencyReportShape = {
   +platformDetails: PlatformDetails,
-  +beforeAction: { +[id: string]: RawThreadInfo },
+  +beforeAction: RawThreadInfos,
   +action: BaseAction,
-  +pollResult?: { +[id: string]: RawThreadInfo },
-  +pushResult: { +[id: string]: RawThreadInfo },
+  +pollResult?: RawThreadInfos,
+  +pushResult: RawThreadInfos,
   +lastActionTypes?: $ReadOnlyArray<$PropertyType<BaseAction, 'type'>>,
   +lastActions?: $ReadOnlyArray<ActionSummary>,
   +time?: number,
@@ -142,9 +142,9 @@
 
 export type ClientThreadInconsistencyReportShape = {
   +platformDetails: PlatformDetails,
-  +beforeAction: { +[id: string]: RawThreadInfo },
+  +beforeAction: RawThreadInfos,
   +action: BaseAction,
-  +pushResult: { +[id: string]: RawThreadInfo },
+  +pushResult: RawThreadInfos,
   +lastActions: $ReadOnlyArray<ActionSummary>,
   +time: number,
 };
diff --git a/lib/types/session-types.js b/lib/types/session-types.js
--- a/lib/types/session-types.js
+++ b/lib/types/session-types.js
@@ -5,7 +5,7 @@
 import type { LogInActionSource } from './account-types.js';
 import type { Shape } from './core.js';
 import type { CalendarQuery } from './entry-types.js';
-import type { RawThreadInfo } from './thread-types.js';
+import type { RawThreadInfos } from './thread-types.js';
 import {
   type UserInfo,
   type CurrentUserInfo,
@@ -53,14 +53,14 @@
 export type ServerSessionChange =
   | {
       cookieInvalidated: false,
-      threadInfos: { +[id: string]: RawThreadInfo },
+      threadInfos: RawThreadInfos,
       userInfos: $ReadOnlyArray<UserInfo>,
       sessionID?: null | string,
       cookie?: string,
     }
   | {
       cookieInvalidated: true,
-      threadInfos: { +[id: string]: RawThreadInfo },
+      threadInfos: RawThreadInfos,
       userInfos: $ReadOnlyArray<UserInfo>,
       currentUserInfo: LoggedOutUserInfo,
       sessionID?: null | string,
diff --git a/lib/types/socket-types.js b/lib/types/socket-types.js
--- a/lib/types/socket-types.js
+++ b/lib/types/socket-types.js
@@ -33,7 +33,7 @@
   type ClientClientResponse,
 } from './request-types.js';
 import type { SessionState, SessionIdentification } from './session-types.js';
-import { type RawThreadInfo, rawThreadInfoValidator } from './thread-types.js';
+import { rawThreadInfoValidator, type RawThreadInfos } from './thread-types.js';
 import {
   type ClientUpdatesResult,
   type ClientUpdatesResultWithUserInfos,
@@ -183,7 +183,7 @@
 export const fullStateSyncActionType = 'FULL_STATE_SYNC';
 export type BaseFullStateSync = {
   +messagesResult: MessagesResponse,
-  +threadInfos: { +[id: string]: RawThreadInfo },
+  +threadInfos: RawThreadInfos,
   +rawEntryInfos: $ReadOnlyArray<RawEntryInfo>,
   +userInfos: $ReadOnlyArray<UserInfo>,
   +updatesCurrentAsOf: number,
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -215,7 +215,7 @@
 };
 
 export type ThreadStore = {
-  +threadInfos: { +[id: string]: RawThreadInfo },
+  +threadInfos: RawThreadInfos,
 };
 export const threadStoreValidator: TInterface<ThreadStore> =
   tShape<ThreadStore>({
@@ -459,7 +459,7 @@
 // in the chat tab if every one of the displayed sidebars is unread
 export const maxUnreadSidebars = 5;
 
-export type ThreadStoreThreadInfos = { +[id: string]: RawThreadInfo };
+export type ThreadStoreThreadInfos = RawThreadInfos;
 
 export type ChatMentionCandidates = { +[id: string]: ResolvedThreadInfo };
 export type ChatMentionCandidatesObj = {
diff --git a/native/redux/edit-thread-permission-migration.js b/native/redux/edit-thread-permission-migration.js
--- a/native/redux/edit-thread-permission-migration.js
+++ b/native/redux/edit-thread-permission-migration.js
@@ -6,6 +6,7 @@
   ThreadCurrentUserInfo,
   RawThreadInfo,
   RoleInfo,
+  RawThreadInfos,
 } from 'lib/types/thread-types.js';
 
 function addDetailedThreadEditPermissionsToUser<
@@ -59,7 +60,7 @@
 
 function migrateThreadStoreForEditThreadPermissions(threadInfos: {
   +[id: string]: RawThreadInfo,
-}): { +[id: string]: RawThreadInfo } {
+}): RawThreadInfos {
   const newThreadInfos = {};
   for (const threadID in threadInfos) {
     const threadInfo: RawThreadInfo = threadInfos[threadID];
diff --git a/native/redux/manage-pins-permission-migration.js b/native/redux/manage-pins-permission-migration.js
--- a/native/redux/manage-pins-permission-migration.js
+++ b/native/redux/manage-pins-permission-migration.js
@@ -5,9 +5,10 @@
   MemberInfo,
   ThreadCurrentUserInfo,
   RoleInfo,
+  RawThreadInfos,
 } from 'lib/types/thread-types.js';
 
-type ThreadStoreThreadInfos = { +[id: string]: RawThreadInfo };
+type ThreadStoreThreadInfos = RawThreadInfos;
 type TargetMemberInfo = MemberInfo | ThreadCurrentUserInfo;
 
 const adminRoleName = 'Admins';
diff --git a/native/selectors/message-selectors.js b/native/selectors/message-selectors.js
--- a/native/selectors/message-selectors.js
+++ b/native/selectors/message-selectors.js
@@ -6,7 +6,7 @@
 import type { ThreadMessageInfo } from 'lib/types/message-types.js';
 import { defaultNumberPerThread } from 'lib/types/message-types.js';
 import type { ThreadActivityStore } from 'lib/types/thread-activity-types.js';
-import { type RawThreadInfo } from 'lib/types/thread-types.js';
+import { type RawThreadInfos } from 'lib/types/thread-types.js';
 
 import { activeThreadSelector } from '../navigation/nav-selectors.js';
 import type { AppState } from '../redux/state-types.js';
@@ -19,7 +19,7 @@
     (state: AppState) => state.threadStore.threadInfos,
     (state: AppState) => state.threadActivityStore,
     (
-      threadInfos: { +[id: string]: RawThreadInfo },
+      threadInfos: RawThreadInfos,
       threadActivityStore: ThreadActivityStore,
     ): ?number => {
       let nextTime;
diff --git a/web/redux/nav-reducer.js b/web/redux/nav-reducer.js
--- a/web/redux/nav-reducer.js
+++ b/web/redux/nav-reducer.js
@@ -2,7 +2,7 @@
 
 import { pendingToRealizedThreadIDsSelector } from 'lib/selectors/thread-selectors.js';
 import { threadIsPending } from 'lib/shared/thread-utils.js';
-import type { RawThreadInfo } from 'lib/types/thread-types.js';
+import type { RawThreadInfos } from 'lib/types/thread-types.js';
 
 import { updateNavInfoActionType } from '../redux/action-types.js';
 import type { Action } from '../redux/redux-setup.js';
@@ -11,7 +11,7 @@
 export default function reduceNavInfo(
   oldState: NavInfo,
   action: Action,
-  newThreadInfos: { +[id: string]: RawThreadInfo },
+  newThreadInfos: RawThreadInfos,
 ): NavInfo {
   let state = oldState;
   if (action.type === updateNavInfoActionType) {
diff --git a/web/selectors/thread-selectors.js b/web/selectors/thread-selectors.js
--- a/web/selectors/thread-selectors.js
+++ b/web/selectors/thread-selectors.js
@@ -16,7 +16,7 @@
   ComposableMessageInfo,
   RobotextMessageInfo,
 } from 'lib/types/message-types.js';
-import type { ThreadInfo, RawThreadInfo } from 'lib/types/thread-types.js';
+import type { ThreadInfo, RawThreadInfos } from 'lib/types/thread-types.js';
 import { values } from 'lib/utils/objects.js';
 
 import { getDefaultTextMessageRules } from '../markdown/rules.react.js';
@@ -140,10 +140,7 @@
   createSelector(
     (state: AppState) => state.threadStore.threadInfos,
     (state: AppState) => state.communityPickerStore.chat,
-    (
-      threadInfos: { +[id: string]: RawThreadInfo },
-      communityID: ?string,
-    ): number =>
+    (threadInfos: RawThreadInfos, communityID: ?string): number =>
       values(threadInfos).filter(
         threadInfo =>
           threadInHomeChatList(threadInfo) &&