diff --git a/lib/selectors/user-selectors.js b/lib/selectors/user-selectors.js
--- a/lib/selectors/user-selectors.js
+++ b/lib/selectors/user-selectors.js
@@ -11,12 +11,12 @@
 import SentencePrefixSearchIndex from '../shared/sentence-prefix-search-index.js';
 import { getSingleOtherUser } from '../shared/thread-utils.js';
 import type { ClientEmojiAvatar } from '../types/avatar-types';
+import type { MinimallyEncodedRawThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
 import type { BaseAppState } from '../types/redux-types.js';
 import { userRelationshipStatus } from '../types/relationship-types.js';
 import { threadTypes } from '../types/thread-types-enum.js';
 import type {
   LegacyRawThreadInfo,
-  LegacyRelativeMemberInfo,
   RelativeMemberInfo,
   RawThreadInfos,
 } from '../types/thread-types.js';
@@ -54,46 +54,68 @@
   return relativeUserInfos;
 }
 
-function getRelativeMemberInfos(
-  threadInfo: ?LegacyRawThreadInfo,
+type ExtractArrayParam = <T>(arr: $ReadOnlyArray<T>) => T;
+
+function getRelativeMemberInfos<
+  TI: MinimallyEncodedRawThreadInfo | LegacyRawThreadInfo,
+>(
+  threadInfo: ?TI,
   currentUserID: ?string,
   userInfos: UserInfos,
-): $ReadOnlyArray<LegacyRelativeMemberInfo> {
-  const relativeMemberInfos = [];
+): $ReadOnlyArray<
+  $ReadOnly<{
+    ...$Call<ExtractArrayParam, $PropertyType<TI, 'members'>>,
+    +username: ?string,
+    +isViewer: boolean,
+  }>,
+> {
+  const relativeMemberInfos: Array<
+    $ReadOnly<{
+      ...$Call<ExtractArrayParam, $PropertyType<TI, 'members'>>,
+      +username: ?string,
+      +isViewer: boolean,
+    }>,
+  > = [];
   if (!threadInfo) {
     return relativeMemberInfos;
   }
   const memberInfos = threadInfo.members;
-  for (const memberInfo of memberInfos) {
+  for (const memberInfoInput of memberInfos) {
+    const memberInfo: $Call<
+      ExtractArrayParam,
+      $PropertyType<TI, 'members'>,
+    > = memberInfoInput;
     if (!memberInfo.role) {
       continue;
     }
-    const username = userInfos[memberInfo.id]
+    const username: ?string = userInfos[memberInfo.id]
       ? userInfos[memberInfo.id].username
       : null;
-    if (memberInfo.id === currentUserID) {
-      relativeMemberInfos.unshift({
-        ...memberInfo,
-        username,
-        isViewer: true,
-      });
+    const isViewer: boolean = memberInfo.id === currentUserID;
+    const relativeMemberInfo: $ReadOnly<{
+      ...$Call<ExtractArrayParam, $PropertyType<TI, 'members'>>,
+      +username: ?string,
+      +isViewer: boolean,
+    }> = {
+      ...memberInfo,
+      username,
+      isViewer,
+    };
+    if (isViewer) {
+      relativeMemberInfos.unshift(relativeMemberInfo);
     } else {
-      relativeMemberInfos.push({
-        ...memberInfo,
-        username,
-        isViewer: false,
-      });
+      relativeMemberInfos.push(relativeMemberInfo);
     }
   }
   return relativeMemberInfos;
 }
 
-const emptyArray: $ReadOnlyArray<LegacyRelativeMemberInfo> = [];
+const emptyArray: $ReadOnlyArray<RelativeMemberInfo> = [];
 
 // Includes current user at the start
 const baseRelativeMemberInfoSelectorForMembersOfThread: (
   threadID: ?string,
-) => (state: BaseAppState<>) => $ReadOnlyArray<LegacyRelativeMemberInfo> = (
+) => (state: BaseAppState<>) => $ReadOnlyArray<RelativeMemberInfo> = (
   threadID: ?string,
 ) => {
   if (!threadID) {