diff --git a/lib/selectors/calendar-filter-selectors.js b/lib/selectors/calendar-filter-selectors.js
--- a/lib/selectors/calendar-filter-selectors.js
+++ b/lib/selectors/calendar-filter-selectors.js
@@ -27,9 +27,9 @@
 }
 
 const filteredThreadIDsSelector: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => ?$ReadOnlySet<string> = createSelector(
-  (state: BaseAppState<*>) => state.calendarFilters,
+  (state: BaseAppState<>) => state.calendarFilters,
   filteredThreadIDs,
 );
 
@@ -53,9 +53,9 @@
 }
 
 const nonThreadCalendarFiltersSelector: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<CalendarFilter> = createSelector(
-  (state: BaseAppState<*>) => state.calendarFilters,
+  (state: BaseAppState<>) => state.calendarFilters,
   nonThreadCalendarFilters,
 );
 
@@ -66,9 +66,9 @@
 }
 
 const nonExcludeDeletedCalendarFiltersSelector: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<CalendarFilter> = createSelector(
-  (state: BaseAppState<*>) => state.calendarFilters,
+  (state: BaseAppState<>) => state.calendarFilters,
   nonExcludeDeletedCalendarFilters,
 );
 
@@ -84,9 +84,9 @@
   return false;
 }
 
-const includeDeletedSelector: (state: BaseAppState<*>) => boolean =
+const includeDeletedSelector: (state: BaseAppState<>) => boolean =
   createSelector(
-    (state: BaseAppState<*>) => state.calendarFilters,
+    (state: BaseAppState<>) => state.calendarFilters,
     (calendarFilters: $ReadOnlyArray<CalendarFilter>) =>
       !filterExists(calendarFilters, calendarThreadFilterTypes.NOT_DELETED),
   );
diff --git a/lib/selectors/chat-selectors.js b/lib/selectors/chat-selectors.js
--- a/lib/selectors/chat-selectors.js
+++ b/lib/selectors/chat-selectors.js
@@ -76,12 +76,12 @@
   +pendingPersonalThreadUserInfo?: UserInfo,
 };
 
-const messageInfoSelector: (state: BaseAppState<*>) => {
+const messageInfoSelector: (state: BaseAppState<>) => {
   +[id: string]: ?MessageInfo,
 } = createObjectSelector(
-  (state: BaseAppState<*>) => state.messageStore.messages,
-  (state: BaseAppState<*>) => state.currentUserInfo && state.currentUserInfo.id,
-  (state: BaseAppState<*>) => state.userStore.userInfos,
+  (state: BaseAppState<>) => state.messageStore.messages,
+  (state: BaseAppState<>) => state.currentUserInfo && state.currentUserInfo.id,
+  (state: BaseAppState<>) => state.userStore.userInfos,
   threadInfoSelector,
   createMessageInfo,
 );
@@ -201,10 +201,10 @@
   };
 }
 
-const chatListData: (state: BaseAppState<*>) => $ReadOnlyArray<ChatThreadItem> =
+const chatListData: (state: BaseAppState<>) => $ReadOnlyArray<ChatThreadItem> =
   createSelector(
     threadInfoSelector,
-    (state: BaseAppState<*>) => state.messageStore,
+    (state: BaseAppState<>) => state.messageStore,
     messageInfoSelector,
     sidebarInfoSelector,
     (
@@ -565,11 +565,11 @@
   additionalMessages: $ReadOnlyArray<MessageInfo>,
 ) =>
   createSelector(
-    (state: BaseAppState<*>) => state.messageStore,
+    (state: BaseAppState<>) => state.messageStore,
     messageInfoSelector,
     threadInfoSelector,
     threadInfoFromSourceMessageIDSelector,
-    (state: BaseAppState<*>) =>
+    (state: BaseAppState<>) =>
       state.currentUserInfo && state.currentUserInfo.id,
     (
       messageStore: MessageStore,
@@ -596,8 +596,7 @@
 const messageListData: (
   threadID: ?string,
   additionalMessages: $ReadOnlyArray<MessageInfo>,
-) => (state: BaseAppState<*>) => MessageListData =
-  memoize2(baseMessageListData);
+) => (state: BaseAppState<>) => MessageListData = memoize2(baseMessageListData);
 
 export type UseMessageListDataArgs = {
   +searching: boolean,
diff --git a/lib/selectors/loading-selectors.js b/lib/selectors/loading-selectors.js
--- a/lib/selectors/loading-selectors.js
+++ b/lib/selectors/loading-selectors.js
@@ -43,12 +43,12 @@
 const baseCreateLoadingStatusSelector = (
   actionTypes: ActionTypes<*, *, *>,
   overrideKey?: string,
-): ((state: BaseAppState<*>) => LoadingStatus) => {
+): ((state: BaseAppState<>) => LoadingStatus) => {
   // This makes sure that reduceLoadingStatuses tracks this action
   registerFetchKey(actionTypes);
   const trackingKey = getTrackingKey(actionTypes, overrideKey);
   return createSelector(
-    (state: BaseAppState<*>) => state.loadingStatuses[trackingKey],
+    (state: BaseAppState<>) => state.loadingStatuses[trackingKey],
     (loadingStatusInfo: { [idx: number]: LoadingStatus }) =>
       loadingStatusFromInfo(loadingStatusInfo),
   );
@@ -57,7 +57,7 @@
 const createLoadingStatusSelector: (
   actionTypes: ActionTypes<*, *, *>,
   overrideKey?: string,
-) => (state: BaseAppState<*>) => LoadingStatus = _memoize(
+) => (state: BaseAppState<>) => LoadingStatus = _memoize(
   baseCreateLoadingStatusSelector,
   getTrackingKey,
 );
@@ -77,9 +77,9 @@
   return errorExists ? 'error' : 'inactive';
 }
 
-const globalLoadingStatusSelector: (state: BaseAppState<*>) => LoadingStatus =
+const globalLoadingStatusSelector: (state: BaseAppState<>) => LoadingStatus =
   createSelector(
-    (state: BaseAppState<*>) => state.loadingStatuses,
+    (state: BaseAppState<>) => state.loadingStatuses,
     (loadingStatusInfos: {
       [key: string]: { [idx: number]: LoadingStatus },
     }): LoadingStatus => {
diff --git a/lib/selectors/local-id-selectors.js b/lib/selectors/local-id-selectors.js
--- a/lib/selectors/local-id-selectors.js
+++ b/lib/selectors/local-id-selectors.js
@@ -12,7 +12,7 @@
   return parseInt(matches[1], 10);
 }
 
-function highestLocalIDSelector(state: ?BaseAppState<*>): number {
+function highestLocalIDSelector(state: ?BaseAppState<>): number {
   let highestLocalIDFound = -1;
 
   if (state && state.messageStore) {
diff --git a/lib/selectors/nav-selectors.js b/lib/selectors/nav-selectors.js
--- a/lib/selectors/nav-selectors.js
+++ b/lib/selectors/nav-selectors.js
@@ -41,11 +41,11 @@
 }
 
 const currentCalendarQuery: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => (calendarActive: boolean) => CalendarQuery = createSelector(
-  (state: BaseAppState<*>) => state.entryStore.lastUserInteractionCalendar,
-  (state: BaseAppState<*>) => state.navInfo,
-  (state: BaseAppState<*>) => state.calendarFilters,
+  (state: BaseAppState<>) => state.entryStore.lastUserInteractionCalendar,
+  (state: BaseAppState<>) => state.navInfo,
+  (state: BaseAppState<>) => state.calendarFilters,
   (
     lastUserInteractionCalendar: number,
     navInfo: BaseNavInfo,
diff --git a/lib/selectors/relationship-selectors.js b/lib/selectors/relationship-selectors.js
--- a/lib/selectors/relationship-selectors.js
+++ b/lib/selectors/relationship-selectors.js
@@ -10,9 +10,9 @@
 } from '../types/relationship-types.js';
 import type { UserInfos } from '../types/user-types.js';
 
-const userRelationshipsSelector: (state: BaseAppState<*>) => UserRelationships =
+const userRelationshipsSelector: (state: BaseAppState<>) => UserRelationships =
   createSelector(
-    (state: BaseAppState<*>) => state.userStore.userInfos,
+    (state: BaseAppState<>) => state.userStore.userInfos,
     (userInfos: UserInfos) => {
       const unorderedFriendRequests = [];
       const unorderedFriends = [];
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
@@ -55,18 +55,18 @@
 
 const _mapValuesWithKeys = _mapValues.convert({ cap: false });
 
-type ThreadInfoSelectorType = (state: BaseAppState<*>) => {
+type ThreadInfoSelectorType = (state: BaseAppState<>) => {
   +[id: string]: ThreadInfo,
 };
 const threadInfoSelector: ThreadInfoSelectorType = createObjectSelector(
-  (state: BaseAppState<*>) => state.threadStore.threadInfos,
-  (state: BaseAppState<*>) => state.currentUserInfo && state.currentUserInfo.id,
-  (state: BaseAppState<*>) => state.userStore.userInfos,
+  (state: BaseAppState<>) => state.threadStore.threadInfos,
+  (state: BaseAppState<>) => state.currentUserInfo && state.currentUserInfo.id,
+  (state: BaseAppState<>) => state.userStore.userInfos,
   threadInfoFromRawThreadInfo,
 );
 
 const communityThreadSelector: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<ThreadInfo> = createSelector(
   threadInfoSelector,
   (threadInfos: { +[id: string]: ThreadInfo }) => {
@@ -83,7 +83,7 @@
 );
 
 const canBeOnScreenThreadInfos: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<ThreadInfo> = createSelector(
   threadInfoSelector,
   (threadInfos: { +[id: string]: ThreadInfo }) => {
@@ -100,7 +100,7 @@
 );
 
 const onScreenThreadInfos: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<ThreadInfo> = createSelector(
   filteredThreadIDsSelector,
   canBeOnScreenThreadInfos,
@@ -117,7 +117,7 @@
 );
 
 const onScreenEntryEditableThreadInfos: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlyArray<ThreadInfo> = createSelector(
   onScreenThreadInfos,
   (threadInfos: $ReadOnlyArray<ThreadInfo>) =>
@@ -126,24 +126,24 @@
     ),
 );
 
-const entryInfoSelector: (state: BaseAppState<*>) => {
+const entryInfoSelector: (state: BaseAppState<>) => {
   +[id: string]: EntryInfo,
 } = createObjectSelector(
-  (state: BaseAppState<*>) => state.entryStore.entryInfos,
-  (state: BaseAppState<*>) => state.currentUserInfo && state.currentUserInfo.id,
-  (state: BaseAppState<*>) => state.userStore.userInfos,
+  (state: BaseAppState<>) => state.entryStore.entryInfos,
+  (state: BaseAppState<>) => state.currentUserInfo && state.currentUserInfo.id,
+  (state: BaseAppState<>) => state.userStore.userInfos,
   createEntryInfo,
 );
 
 // "current" means within startDate/endDate range, not deleted, and in
 // onScreenThreadInfos
-const currentDaysToEntries: (state: BaseAppState<*>) => {
+const currentDaysToEntries: (state: BaseAppState<>) => {
   +[dayString: string]: EntryInfo[],
 } = createSelector(
   entryInfoSelector,
-  (state: BaseAppState<*>) => state.entryStore.daysToEntries,
-  (state: BaseAppState<*>) => state.navInfo.startDate,
-  (state: BaseAppState<*>) => state.navInfo.endDate,
+  (state: BaseAppState<>) => state.entryStore.daysToEntries,
+  (state: BaseAppState<>) => state.navInfo.startDate,
+  (state: BaseAppState<>) => state.navInfo.endDate,
   onScreenThreadInfos,
   includeDeletedSelector,
   (
@@ -179,7 +179,7 @@
   },
 );
 
-const childThreadInfos: (state: BaseAppState<*>) => {
+const childThreadInfos: (state: BaseAppState<>) => {
   +[id: string]: $ReadOnlyArray<ThreadInfo>,
 } = createSelector(
   threadInfoSelector,
@@ -214,11 +214,11 @@
   return null;
 }
 
-const sidebarInfoSelector: (state: BaseAppState<*>) => {
+const sidebarInfoSelector: (state: BaseAppState<>) => {
   +[id: string]: $ReadOnlyArray<SidebarInfo>,
 } = createObjectSelector(
   childThreadInfos,
-  (state: BaseAppState<*>) => state.messageStore,
+  (state: BaseAppState<>) => state.messageStore,
   (childThreads: $ReadOnlyArray<ThreadInfo>, messageStore: MessageStore) => {
     const sidebarInfos = [];
     for (const childThreadInfo of childThreads) {
@@ -248,8 +248,8 @@
   },
 );
 
-const unreadCount: (state: BaseAppState<*>) => number = createSelector(
-  (state: BaseAppState<*>) => state.threadStore.threadInfos,
+const unreadCount: (state: BaseAppState<>) => number = createSelector(
+  (state: BaseAppState<>) => state.threadStore.threadInfos,
   (threadInfos: { +[id: string]: RawThreadInfo }): number =>
     values(threadInfos).filter(
       threadInfo =>
@@ -257,20 +257,18 @@
     ).length,
 );
 
-const unreadBackgroundCount: (state: BaseAppState<*>) => number =
-  createSelector(
-    (state: BaseAppState<*>) => state.threadStore.threadInfos,
-    (threadInfos: { +[id: string]: RawThreadInfo }): number =>
-      values(threadInfos).filter(
-        threadInfo =>
-          threadInBackgroundChatList(threadInfo) &&
-          threadInfo.currentUser.unread,
-      ).length,
-  );
+const unreadBackgroundCount: (state: BaseAppState<>) => number = createSelector(
+  (state: BaseAppState<>) => state.threadStore.threadInfos,
+  (threadInfos: { +[id: string]: RawThreadInfo }): number =>
+    values(threadInfos).filter(
+      threadInfo =>
+        threadInBackgroundChatList(threadInfo) && threadInfo.currentUser.unread,
+    ).length,
+);
 
 const baseAncestorThreadInfos = (threadID: string) =>
   createSelector(
-    (state: BaseAppState<*>) => threadInfoSelector(state),
+    (state: BaseAppState<>) => threadInfoSelector(state),
     (threadInfos: {
       +[id: string]: ThreadInfo,
     }): $ReadOnlyArray<ThreadInfo> => {
@@ -287,13 +285,13 @@
 
 const ancestorThreadInfos: (
   threadID: string,
-) => (state: BaseAppState<*>) => $ReadOnlyArray<ThreadInfo> = _memoize(
+) => (state: BaseAppState<>) => $ReadOnlyArray<ThreadInfo> = _memoize(
   baseAncestorThreadInfos,
 );
 
 const baseOtherUsersButNoOtherAdmins = (threadID: string) =>
   createSelector(
-    (state: BaseAppState<*>) => state.threadStore.threadInfos[threadID],
+    (state: BaseAppState<>) => state.threadStore.threadInfos[threadID],
     relativeMemberInfoSelectorForMembersOfThread(threadID),
     (
       threadInfo: ?RawThreadInfo,
@@ -324,7 +322,7 @@
 
 const otherUsersButNoOtherAdmins: (
   threadID: string,
-) => (state: BaseAppState<*>) => boolean = _memoize(
+) => (state: BaseAppState<>) => boolean = _memoize(
   baseOtherUsersButNoOtherAdmins,
 );
 
@@ -359,17 +357,17 @@
   return mostRecent ? mostRecent.threadID : null;
 }
 
-const mostRecentlyReadThreadSelector: (state: BaseAppState<*>) => ?string =
+const mostRecentlyReadThreadSelector: (state: BaseAppState<>) => ?string =
   createSelector(
-    (state: BaseAppState<*>) => state.messageStore,
-    (state: BaseAppState<*>) => state.threadStore.threadInfos,
+    (state: BaseAppState<>) => state.messageStore,
+    (state: BaseAppState<>) => state.threadStore.threadInfos,
     mostRecentlyReadThread,
   );
 
-const threadInfoFromSourceMessageIDSelector: (state: BaseAppState<*>) => {
+const threadInfoFromSourceMessageIDSelector: (state: BaseAppState<>) => {
   +[id: string]: ThreadInfo,
 } = createSelector(
-  (state: BaseAppState<*>) => state.threadStore.threadInfos,
+  (state: BaseAppState<>) => state.threadStore.threadInfos,
   threadInfoSelector,
   (
     rawThreadInfos: { +[id: string]: RawThreadInfo },
@@ -423,8 +421,8 @@
   containingThreadID: ?string,
 ) =>
   createSelector(
-    (state: BaseAppState<*>) => threadInfoSelector(state)[threadID],
-    (state: BaseAppState<*>) =>
+    (state: BaseAppState<>) => threadInfoSelector(state)[threadID],
+    (state: BaseAppState<>) =>
       containingThreadID ? threadInfoSelector(state)[containingThreadID] : null,
     (threadInfo: ThreadInfo, containingThreadInfo: ?ThreadInfo) => {
       return () => {
@@ -440,7 +438,7 @@
 const savedEmojiAvatarSelectorForThread: (
   threadID: string,
   containingThreadID: ?string,
-) => (state: BaseAppState<*>) => () => ClientEmojiAvatar = _memoize(
+) => (state: BaseAppState<>) => () => ClientEmojiAvatar = _memoize(
   baseSavedEmojiAvatarSelectorForThread,
 );
 
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
@@ -101,25 +101,25 @@
     return () => emptyArray;
   }
   return createSelector(
-    (state: BaseAppState<*>) => state.threadStore.threadInfos[threadID],
-    (state: BaseAppState<*>) =>
+    (state: BaseAppState<>) => state.threadStore.threadInfos[threadID],
+    (state: BaseAppState<>) =>
       state.currentUserInfo && state.currentUserInfo.id,
-    (state: BaseAppState<*>) => state.userStore.userInfos,
+    (state: BaseAppState<>) => state.userStore.userInfos,
     getRelativeMemberInfos,
   );
 };
 
 const relativeMemberInfoSelectorForMembersOfThread: (
   threadID: ?string,
-) => (state: BaseAppState<*>) => $ReadOnlyArray<RelativeMemberInfo> = _memoize(
+) => (state: BaseAppState<>) => $ReadOnlyArray<RelativeMemberInfo> = _memoize(
   baseRelativeMemberInfoSelectorForMembersOfThread,
 );
 
-const userInfoSelectorForPotentialMembers: (state: BaseAppState<*>) => {
+const userInfoSelectorForPotentialMembers: (state: BaseAppState<>) => {
   [id: string]: AccountUserInfo,
 } = createSelector(
-  (state: BaseAppState<*>) => state.userStore.userInfos,
-  (state: BaseAppState<*>) => state.currentUserInfo && state.currentUserInfo.id,
+  (state: BaseAppState<>) => state.userStore.userInfos,
+  (state: BaseAppState<>) => state.currentUserInfo && state.currentUserInfo.id,
   (
     userInfos: UserInfos,
     currentUserID: ?string,
@@ -153,22 +153,22 @@
 }
 
 const userSearchIndexForPotentialMembers: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => SearchIndex = createSelector(
   userInfoSelectorForPotentialMembers,
   searchIndexFromUserInfos,
 );
 
-const isLoggedIn = (state: BaseAppState<*>): boolean =>
+const isLoggedIn = (state: BaseAppState<>): boolean =>
   !!(
     state.currentUserInfo &&
     !state.currentUserInfo.anonymous &&
     state.dataLoaded
   );
 
-const userStoreSearchIndex: (state: BaseAppState<*>) => SearchIndex =
+const userStoreSearchIndex: (state: BaseAppState<>) => SearchIndex =
   createSelector(
-    (state: BaseAppState<*>) => state.userStore.userInfos,
+    (state: BaseAppState<>) => state.userStore.userInfos,
     (userInfos: UserInfos) => {
       const searchIndex = new SearchIndex();
       for (const id in userInfos) {
@@ -183,7 +183,7 @@
   );
 
 const usersWithPersonalThreadSelector: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => $ReadOnlySet<string> = createSelector(
   state => state.currentUserInfo && state.currentUserInfo.id,
   state => state.threadStore.threadInfos,
@@ -208,9 +208,9 @@
 );
 
 const savedEmojiAvatarSelectorForCurrentUser: (
-  state: BaseAppState<*>,
+  state: BaseAppState<>,
 ) => () => ClientEmojiAvatar = createSelector(
-  (state: BaseAppState<*>) => state.currentUserInfo && state.currentUserInfo,
+  (state: BaseAppState<>) => state.currentUserInfo && state.currentUserInfo,
   (currentUser: ?CurrentUserInfo) => {
     return () => {
       let userAvatar = getAvatarForUser(currentUser);
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -116,7 +116,7 @@
 import type { Shape } from '../types/core.js';
 import type { NotifPermissionAlertInfo } from '../utils/push-alerts.js';
 
-export type BaseAppState<NavInfo: BaseNavInfo> = {
+export type BaseAppState<NavInfo: BaseNavInfo = BaseNavInfo> = {
   +navInfo: NavInfo,
   +currentUserInfo: ?CurrentUserInfo,
   +draftStore: DraftStore,
@@ -147,11 +147,11 @@
 
 // Web JS runtime doesn't have access to the cookie for security reasons.
 // Native JS doesn't have a sessionID because the cookieID is used instead.
-export type NativeAppState = BaseAppState<*> & {
+export type NativeAppState = BaseAppState<> & {
   +sessionID?: void,
   ...
 };
-export type WebAppState = BaseAppState<*> & {
+export type WebAppState = BaseAppState<> & {
   +sessionID: ?string,
   +cryptoStore: CryptoStore,
   +pushApiPublicKey: ?string,
@@ -476,7 +476,7 @@
     }
   | {
       +type: 'persist/REHYDRATE',
-      +payload: ?BaseAppState<*>,
+      +payload: ?BaseAppState<>,
     }
   | {
       +type: 'FETCH_MESSAGES_BEFORE_CURSOR_STARTED',