Skip to content

Commit

Permalink
types: Mark most arrays as read-only
Browse files Browse the repository at this point in the history
Done with:

  $ perl -i -0pe '
          s<( \w+ ) \[\]> (\$ReadOnlyArray<$1>)gsmx;
          s/\bArray\b</\$ReadOnlyArray</g
        ' src/**/*.js
  $ tools/fmt

followed by reviewing the changes, and reverting those that weren't
appropriate (which were perhaps 1/3 of the total) with commands like
`git restore -p src/foo/bar.js`.
  • Loading branch information
gnprice committed Jan 8, 2022
1 parent 8fec737 commit 1a281fa
Show file tree
Hide file tree
Showing 69 changed files with 145 additions and 119 deletions.
6 changes: 3 additions & 3 deletions src/__tests__/lib/exampleData.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ const randMessageId: () => number = makeUniqueRandInt('message ID', 10000000);
export const pmMessage = (args?: {|
...$Rest<PmMessage, { ... }>,
sender?: User,
recipients?: User[],
recipients?: $ReadOnlyArray<User>,
sender_id?: number, // accept a plain number, for convenience in tests
|}): PmMessage => {
// The `Object.freeze` is to work around a Flow issue:
Expand Down Expand Up @@ -395,7 +395,7 @@ export const pmMessage = (args?: {|

export const pmMessageFromTo = (
from: User,
to: User[],
to: $ReadOnlyArray<User>,
extra?: $Rest<PmMessage, { ... }>,
): PmMessage => pmMessage({ sender: from, recipients: [from, ...to], ...extra });

Expand Down Expand Up @@ -444,7 +444,7 @@ export const streamMessage = (args?: {|
};

/** Construct a MessagesState from a list of messages. */
export const makeMessagesState = (messages: Message[]): MessagesState =>
export const makeMessagesState = (messages: $ReadOnlyArray<Message>): MessagesState =>
Immutable.Map(messages.map(m => [m.id, m]));

/* ========================================================================
Expand Down
2 changes: 1 addition & 1 deletion src/animation/AnimatedRotateComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class AnimatedRotateComponent extends PureComponent<Props> {
const { children, style } = this.props;
const rotation = this.rotation.interpolate({
inputRange: [0, 360],
outputRange: (['0deg', '360deg']: string[]),
outputRange: (['0deg', '360deg']: $ReadOnlyArray<string>),
});
const animatedStyle = { transform: [{ rotate: rotation }] };

Expand Down
4 changes: 2 additions & 2 deletions src/api/devListUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { apiGet } from './apiFetch';

type ApiResponseDevListUsers = {|
...$Exact<ApiResponseSuccess>,
direct_admins: DevUser[],
direct_users: DevUser[],
direct_admins: $ReadOnlyArray<DevUser>,
direct_users: $ReadOnlyArray<DevUser>,
|};

export default (auth: Auth): Promise<ApiResponseDevListUsers> => apiGet(auth, 'dev_list_users');
2 changes: 1 addition & 1 deletion src/api/getTopics.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiGet } from './apiFetch';

type ApiResponseTopics = {|
...$Exact<ApiResponseSuccess>,
topics: Topic[],
topics: $ReadOnlyArray<Topic>,
|};

/** See https://zulip.com/api/get-stream-topics */
Expand Down
6 changes: 3 additions & 3 deletions src/api/messages/__tests__/migrateMessages-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ describe('migrateMessages', () => {
avatar_url: null,
};

const input: ServerMessage[] = [serverMessage];
const input: $ReadOnlyArray<ServerMessage> = [serverMessage];

const expectedOutput: Message[] = [
const expectedOutput: $ReadOnlyArray<Message> = [
{
...serverMessage,
reactions: [
Expand All @@ -43,7 +43,7 @@ describe('migrateMessages', () => {
},
];

const actualOutput: Message[] = migrateMessages(input, identityOfAuth(eg.selfAuth));
const actualOutput: $ReadOnlyArray<Message> = migrateMessages(input, identityOfAuth(eg.selfAuth));

test('In reactions, replace user object with `user_id`', () => {
expect(actualOutput.map(m => m.reactions)).toEqual(expectedOutput.map(m => m.reactions));
Expand Down
2 changes: 1 addition & 1 deletion src/api/messages/getMessageHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiGet } from '../apiFetch';

type ApiResponseMessageHistory = {|
...$Exact<ApiResponseSuccess>,
message_history: MessageSnapshot[],
message_history: $ReadOnlyArray<MessageSnapshot>,
|};

/** See https://zulip.com/api/get-message-history */
Expand Down
4 changes: 2 additions & 2 deletions src/api/messages/getMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type ApiResponseMessages = {|
found_anchor: boolean,
found_newest: boolean,
found_oldest: boolean,
messages: Message[],
messages: $ReadOnlyArray<Message>,
|};

/**
Expand Down Expand Up @@ -49,7 +49,7 @@ export type ServerMessage = ServerMessageOf<PmMessage> | ServerMessageOf<StreamM
// `ApiResponseMessages` before returning it to application code.
type ServerApiResponseMessages = {|
...ApiResponseMessages,
messages: ServerMessage[],
messages: $ReadOnlyArray<ServerMessage>,
|};

/** Exported for tests only. */
Expand Down
2 changes: 1 addition & 1 deletion src/api/messages/messagesFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { apiPost } from '../apiFetch';

export type ApiResponseMessagesFlags = {|
...$Exact<ApiResponseSuccess>,
messages: number[],
messages: $ReadOnlyArray<number>,
|};

export default (
Expand Down
2 changes: 1 addition & 1 deletion src/api/messages/toggleMessageStarred.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ApiResponseMessagesFlags } from './messagesFlags';

export default (
auth: Auth,
messageIds: number[],
messageIds: $ReadOnlyArray<number>,
starMessage: boolean,
): Promise<ApiResponseMessagesFlags> =>
messagesFlags(auth, messageIds, starMessage ? 'add' : 'remove', 'starred');
2 changes: 1 addition & 1 deletion src/api/pollForEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiGet } from './apiFetch';

type ApiResponsePollEvents = {|
...$Exact<ApiResponseSuccess>,
events: GeneralEvent[],
events: $ReadOnlyArray<GeneralEvent>,
|};

/** See https://zulip.com/api/get-events */
Expand Down
2 changes: 1 addition & 1 deletion src/api/queueMarkAsRead.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const processQueue = async (auth: Auth) => {
unackedMessageIds = unackedMessageIds.filter(id => !acked_messages.has(id));
};

export default (auth: Auth, messageIds: number[]): void => {
export default (auth: Auth, messageIds: $ReadOnlyArray<number>): void => {
unackedMessageIds.push(...messageIds);
processQueue(auth);
};
2 changes: 1 addition & 1 deletion src/api/settings/getServerSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type ApiResponseServerSettings = {|
authentication_methods: AuthenticationMethods,
// external_authentication_methods added for server v2.1
// TODO(server-2.1): Mark this as required; simplify downstream.
external_authentication_methods?: ExternalAuthenticationMethod[],
external_authentication_methods?: $ReadOnlyArray<ExternalAuthenticationMethod>,
email_auth_enabled: boolean,
push_notifications_enabled: boolean,
realm_description: string,
Expand Down
2 changes: 1 addition & 1 deletion src/api/streams/createStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default (
auth: Auth,
name: string,
description?: string = '',
principals?: string[] = [],
principals?: $ReadOnlyArray<string> = [],
inviteOnly?: boolean = false,
announce?: boolean = false,
): Promise<ApiResponse> =>
Expand Down
2 changes: 1 addition & 1 deletion src/api/streams/getStreams.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiGet } from '../apiFetch';

type ApiResponseStreams = {|
...$Exact<ApiResponseSuccess>,
streams: Stream[],
streams: $ReadOnlyArray<Stream>,
|};

/** See https://zulip.com/api/get-streams */
Expand Down
2 changes: 1 addition & 1 deletion src/api/subscriptions/getSubscriptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiGet } from '../apiFetch';

type ApiResponseSubscriptions = {|
...$Exact<ApiResponseSuccess>,
subscriptions: Subscription[],
subscriptions: $ReadOnlyArray<Subscription>,
|};

/** See https://zulip.com/api/get-subscriptions */
Expand Down
4 changes: 2 additions & 2 deletions src/api/subscriptions/subscriptionAdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ type SubscriptionObj = {|
/** See https://zulip.com/api/subscribe */
export default (
auth: Auth,
subscriptions: SubscriptionObj[],
principals?: string[],
subscriptions: $ReadOnlyArray<SubscriptionObj>,
principals?: $ReadOnlyArray<string>,
): Promise<ApiResponse> =>
apiPost(auth, 'users/me/subscriptions', {
subscriptions: JSON.stringify(subscriptions),
Expand Down
6 changes: 5 additions & 1 deletion src/api/subscriptions/subscriptionRemove.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type { ApiResponse, Auth } from '../transportTypes';
import { apiDelete } from '../apiFetch';

/** See https://zulip.com/api/unsubscribe */
export default (auth: Auth, subscriptions: string[], principals?: string[]): Promise<ApiResponse> =>
export default (
auth: Auth,
subscriptions: $ReadOnlyArray<string>,
principals?: $ReadOnlyArray<string>,
): Promise<ApiResponse> =>
apiDelete(auth, 'users/me/subscriptions', {
subscriptions: JSON.stringify(subscriptions),
principals: JSON.stringify(principals),
Expand Down
6 changes: 3 additions & 3 deletions src/boot/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ if (process.env.NODE_ENV === 'development') {
* the lists of properties we do persist, below.
*/
// prettier-ignore
export const discardKeys: Array<$Keys<GlobalState>> = [
export const discardKeys: $ReadOnlyArray<$Keys<GlobalState>> = [
'alertWords', 'caughtUp', 'fetching',
'presence', 'session', 'topics', 'typing', 'userStatus',
];
Expand All @@ -57,7 +57,7 @@ export const discardKeys: Array<$Keys<GlobalState>> = [
* persist them.
*/
// prettier-ignore
export const storeKeys: Array<$Keys<GlobalState>> = [
export const storeKeys: $ReadOnlyArray<$Keys<GlobalState>> = [
'migrations', 'accounts', 'drafts', 'outbox', 'settings',
];

Expand All @@ -69,7 +69,7 @@ export const storeKeys: Array<$Keys<GlobalState>> = [
* don't have to re-download it.
*/
// prettier-ignore
export const cacheKeys: Array<$Keys<GlobalState>> = [
export const cacheKeys: $ReadOnlyArray<$Keys<GlobalState>> = [
'flags', 'messages', 'mute', 'mutedUsers', 'narrows', 'pmConversations',
'realm', 'streams', 'subscriptions', 'unread', 'userGroups', 'users',
];
Expand Down
2 changes: 1 addition & 1 deletion src/chat/narrowsSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const getFetchedMessageIdsForNarrow = (
narrow: Narrow,
): $ReadOnlyArray<number> => getAllNarrows(state).get(keyFromNarrow(narrow)) || NULL_ARRAY;

const getFetchedMessagesForNarrow: Selector<Message[], Narrow> = createSelector(
const getFetchedMessagesForNarrow: Selector<$ReadOnlyArray<Message>, Narrow> = createSelector(
getFetchedMessageIdsForNarrow,
state => getMessages(state),
(messageIds, messages) =>
Expand Down
2 changes: 1 addition & 1 deletion src/common/GroupAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const styles = createStyleSheet({
});

type Props = $ReadOnly<{|
names: string[],
names: $ReadOnlyArray<string>,
size: number,
children?: Node,
onPress?: () => void,
Expand Down
2 changes: 1 addition & 1 deletion src/compose/ComposeBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ class ComposeBoxInner extends PureComponent<Props, State> {
}
};

insertAttachment = async (attachments: DocumentPickerResponse[]) => {
insertAttachment = async (attachments: $ReadOnlyArray<DocumentPickerResponse>) => {
this.setState(({ numUploading }) => ({
numUploading: numUploading + 1,
}));
Expand Down
4 changes: 2 additions & 2 deletions src/compose/ComposeMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { androidEnsureStoragePermission } from '../lightbox/download';
type OuterProps = $ReadOnly<{|
expanded: boolean,
destinationNarrow: Narrow,
insertAttachment: (DocumentPickerResponse[]) => Promise<void>,
insertAttachment: ($ReadOnlyArray<DocumentPickerResponse>) => Promise<void>,
insertVideoCallLink: (() => void) | null,
onExpandContract: () => void,
|}>;
Expand Down Expand Up @@ -206,7 +206,7 @@ class ComposeMenuInner extends PureComponent<Props> {
try {
response = (await DocumentPicker.pickMultiple({
type: [DocumentPicker.types.allFiles],
}): DocumentPickerResponse[]);
}): $ReadOnlyArray<DocumentPickerResponse>);
} catch (e) {
if (!DocumentPicker.isCancel(e)) {
showErrorAlert(_('Error'), e);
Expand Down
2 changes: 1 addition & 1 deletion src/compose/MentionWarnings.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function MentionWarningsInner(props: Props, ref): Node {
const auth = useSelector(getAuth);
const allUsersById = useSelector(getAllUsersById);

const [unsubscribedMentions, setUnsubscribedMentions] = useState<UserId[]>([]);
const [unsubscribedMentions, setUnsubscribedMentions] = useState<$ReadOnlyArray<UserId>>([]);

const _ = useContext(TranslationContext);

Expand Down
2 changes: 1 addition & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Config = {|
enableReduxSlowReducerWarnings: boolean,
slowReducersThreshold: number,
enableErrorConsoleLogging: boolean,
appOwnDomains: string[],
appOwnDomains: $ReadOnlyArray<string>,
|};

const config: Config = {
Expand Down
2 changes: 1 addition & 1 deletion src/lightbox/LightboxActionSheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const shareImageDirectly = ({ src, auth }: DownloadImageType) => {
shareImage(src, auth);
};

const actionSheetButtons: ButtonType[] = [
const actionSheetButtons: $ReadOnlyArray<ButtonType> = [
{ title: 'Download image', onPress: tryToDownloadImage },
{ title: 'Share image', onPress: shareImageDirectly },
{ title: 'Share link to image', onPress: shareLink },
Expand Down
2 changes: 1 addition & 1 deletion src/message/NoMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type EmptyMessage = {|
text: string,
|};

const messages: EmptyMessage[] = [
const messages: $ReadOnlyArray<EmptyMessage> = [
{ isFunc: isHomeNarrow, text: 'No messages on server' },
{ isFunc: isSpecialNarrow, text: 'No messages' },
{ isFunc: isStreamNarrow, text: 'No messages in stream' },
Expand Down
6 changes: 3 additions & 3 deletions src/message/fetchActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const messageFetchError = (args: {| narrow: Narrow, error: Error |}): PerAccount
};

const messageFetchComplete = (args: {|
messages: Message[],
messages: $ReadOnlyArray<Message>,
narrow: Narrow,
anchor: number,
numBefore: number,
Expand Down Expand Up @@ -111,7 +111,7 @@ export const fetchMessages = (fetchArgs: {|
anchor: number,
numBefore: number,
numAfter: number,
|}): ThunkAction<Promise<Message[]>> => async (dispatch, getState) => {
|}): ThunkAction<Promise<$ReadOnlyArray<Message>>> => async (dispatch, getState) => {
dispatch(messageFetchStart(fetchArgs.narrow, fetchArgs.numBefore, fetchArgs.numAfter));
try {
const { messages, found_newest, found_oldest } =
Expand Down Expand Up @@ -308,7 +308,7 @@ export const isFetchNeededAtAnchor = (
export const fetchMessagesInNarrow = (
narrow: Narrow,
anchor: number = FIRST_UNREAD_ANCHOR,
): ThunkAction<Promise<Message[] | void>> => async (dispatch, getState) => {
): ThunkAction<Promise<$ReadOnlyArray<Message> | void>> => async (dispatch, getState) => {
if (!isFetchNeededAtAnchor(getState(), narrow, anchor)) {
return undefined;
}
Expand Down
2 changes: 1 addition & 1 deletion src/message/messageSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function truncateForLogging<T: JSONable>(arr: $ReadOnlyArray<T>, len = 10): JSON
};
}

export const getPrivateMessages: Selector<PmMessage[]> = createSelector(
export const getPrivateMessages: Selector<$ReadOnlyArray<PmMessage>> = createSelector(
getAllNarrows,
getMessages,
(narrows, messages) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pm-conversations/PmConversationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const styles = createStyleSheet({
});

type Props = $ReadOnly<{|
conversations: PmConversationData[],
conversations: $ReadOnlyArray<PmConversationData>,
|}>;

/**
Expand Down
2 changes: 1 addition & 1 deletion src/pm-conversations/pmConversationsModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function keyOfExactUsers(ids: UserId[]): PmConversationKey {
}

// Input may contain self or not, and needn't be sorted.
function keyOfUsers(ids: UserId[], ownUserId: UserId): PmConversationKey {
function keyOfUsers(ids: $ReadOnlyArray<UserId>, ownUserId: UserId): PmConversationKey {
return keyOfExactUsers(ids.filter(id => id !== ownUserId));
}

Expand Down
Loading

0 comments on commit 1a281fa

Please sign in to comment.