Improve types

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-10-27 20:36:32 +01:00
parent f542796da5
commit 4cccfcdff1
13 changed files with 141 additions and 51 deletions

View file

@ -24,7 +24,7 @@ const createApp = (params: CreateApplicationParams, baseURL?: string) =>
return client.apps.createApplication(params).then((app) => {
dispatch({ type: APP_CREATE_SUCCESS, params, app });
return app as Record<string, string>;
return app;
}).catch(error => {
dispatch({ type: APP_CREATE_FAIL, params, error });
throw error;

View file

@ -6,7 +6,14 @@
* @see module:pl-fe/actions/oauth
* @see module:pl-fe/actions/security
*/
import { credentialAccountSchema, PlApiClient, type CreateAccountParams, type Token } from 'pl-api';
import {
credentialAccountSchema,
PlApiClient,
type Application,
type CreateAccountParams,
type CredentialAccount,
type Token,
} from 'pl-api';
import { defineMessages } from 'react-intl';
import * as v from 'valibot';
@ -32,6 +39,7 @@ import { type PlfeResponse, getClient } from '../api';
import { importEntities } from './importer';
import type { Account } from 'pl-fe/normalizers/account';
import type { AppDispatch, RootState } from 'pl-fe/store';
const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT' as const;
@ -49,6 +57,69 @@ const AUTH_ACCOUNT_REMEMBER_REQUEST = 'AUTH_ACCOUNT_REMEMBER_REQUEST' as const;
const AUTH_ACCOUNT_REMEMBER_SUCCESS = 'AUTH_ACCOUNT_REMEMBER_SUCCESS' as const;
const AUTH_ACCOUNT_REMEMBER_FAIL = 'AUTH_ACCOUNT_REMEMBER_FAIL' as const;
interface SwitchAccountAction {
type: typeof SWITCH_ACCOUNT;
account?: Account;
background: boolean;
}
interface AuthAppCreatedAction {
type: typeof AUTH_APP_CREATED;
app: Application;
}
interface AuthAppAuthorizedAction {
type: typeof AUTH_APP_AUTHORIZED;
app: Application;
token: Token;
}
interface AuthLoggedInAction {
type: typeof AUTH_LOGGED_IN;
token: Token;
}
interface AuthLoggedOutAction {
type: typeof AUTH_LOGGED_OUT;
account: Account;
standalone: boolean;
}
interface VerifyCredentialsRequestAction {
type: typeof VERIFY_CREDENTIALS_REQUEST;
token: string;
}
interface VerifyCredentialsSuccessAction {
type: typeof VERIFY_CREDENTIALS_SUCCESS;
token: string;
account: CredentialAccount;
}
interface VerifyCredentialsFailAction {
type: typeof VERIFY_CREDENTIALS_FAIL;
token: string;
error: any;
}
interface AuthAccountRememberRequestAction {
type: typeof AUTH_ACCOUNT_REMEMBER_REQUEST;
accountUrl: string;
}
interface AuthAccountRememberSuccessAction {
type: typeof AUTH_ACCOUNT_REMEMBER_SUCCESS;
accountUrl: string;
account: CredentialAccount;
}
interface AuthAccountRememberFailAction {
type: typeof AUTH_ACCOUNT_REMEMBER_FAIL;
error: any;
accountUrl: string;
skipAlert: boolean;
}
const customApp = custom('app');
const messages = defineMessages({
@ -69,7 +140,7 @@ const createAppAndToken = () =>
const getAuthApp = () =>
(dispatch: AppDispatch) => {
if (customApp?.client_secret) {
return noOp().then(() => dispatch({ type: AUTH_APP_CREATED, app: customApp }));
return noOp().then(() => dispatch<AuthAppCreatedAction>({ type: AUTH_APP_CREATED, app: customApp }));
} else {
return dispatch(createAuthApp());
}
@ -84,25 +155,25 @@ const createAuthApp = () =>
website: sourceCode.homepage,
};
return dispatch(createApp(params)).then((app: Record<string, string>) =>
dispatch({ type: AUTH_APP_CREATED, app }),
return dispatch(createApp(params)).then((app) =>
dispatch<AuthAppCreatedAction>({ type: AUTH_APP_CREATED, app }),
);
};
const createAppToken = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const app = getState().auth.app;
const app = getState().auth.app!;
const params = {
client_id: app?.client_id!,
client_secret: app?.client_secret!,
client_id: app.client_id!,
client_secret: app.client_secret!,
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
grant_type: 'client_credentials',
scope: getScopes(getState()),
};
return dispatch(obtainOAuthToken(params)).then((token: Record<string, string | number>) =>
dispatch({ type: AUTH_APP_AUTHORIZED, app, token }),
return dispatch(obtainOAuthToken(params)).then((token) =>
dispatch<AuthAppAuthorizedAction>({ type: AUTH_APP_AUTHORIZED, app, token }),
);
};
@ -145,13 +216,13 @@ const verifyCredentials = (token: string, accountUrl?: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const baseURL = parseBaseURL(accountUrl) || BuildConfig.BACKEND_URL;
dispatch({ type: VERIFY_CREDENTIALS_REQUEST, token });
dispatch<VerifyCredentialsRequestAction>({ type: VERIFY_CREDENTIALS_REQUEST, token });
const client = new PlApiClient(baseURL, token);
return client.settings.verifyCredentials().then((account) => {
dispatch(importEntities({ accounts: [account] }));
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
dispatch<VerifyCredentialsSuccessAction>({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
return account;
}).catch(error => {
@ -160,12 +231,12 @@ const verifyCredentials = (token: string, accountUrl?: string) =>
const account = error.response.json;
const parsedAccount = v.parse(credentialAccountSchema, error.response.json);
dispatch(importEntities({ accounts: [parsedAccount] }));
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account: parsedAccount });
dispatch<VerifyCredentialsSuccessAction>({ type: VERIFY_CREDENTIALS_SUCCESS, token, account: parsedAccount });
if (account.id === getState().me) dispatch(fetchMeSuccess(parsedAccount));
return parsedAccount;
} else {
if (getState().me === null) dispatch(fetchMeFail(error));
dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error });
dispatch<VerifyCredentialsFailAction>({ type: VERIFY_CREDENTIALS_FAIL, token, error });
throw error;
}
});
@ -173,14 +244,14 @@ const verifyCredentials = (token: string, accountUrl?: string) =>
const rememberAuthAccount = (accountUrl: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
dispatch<AuthAccountRememberRequestAction>({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => {
dispatch(importEntities({ accounts: [account] }));
dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl });
dispatch<AuthAccountRememberSuccessAction>({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl });
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
return account;
}).catch(error => {
dispatch({ type: AUTH_ACCOUNT_REMEMBER_FAIL, error, accountUrl, skipAlert: true });
dispatch<AuthAccountRememberFailAction>({ type: AUTH_ACCOUNT_REMEMBER_FAIL, error, accountUrl, skipAlert: true });
});
};
@ -227,7 +298,7 @@ const logOut = () =>
// Clear the account from Sentry.
unsetSentryAccount();
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
dispatch<AuthLoggedOutAction>({ type: AUTH_LOGGED_OUT, account, standalone });
toast.success(messages.loggedOut);
});
@ -240,7 +311,7 @@ const switchAccount = (accountId: string, background = false) =>
queryClient.invalidateQueries();
queryClient.clear();
return dispatch({ type: SWITCH_ACCOUNT, account, background });
return dispatch<SwitchAccountAction>({ type: SWITCH_ACCOUNT, account, background });
};
const fetchOwnAccounts = () =>
@ -272,10 +343,23 @@ const fetchCaptcha = () =>
const authLoggedIn = (token: Token) =>
(dispatch: AppDispatch) => {
dispatch({ type: AUTH_LOGGED_IN, token });
dispatch<AuthLoggedInAction>({ type: AUTH_LOGGED_IN, token });
return token;
};
type AuthAction =
| SwitchAccountAction
| AuthAppCreatedAction
| AuthAppAuthorizedAction
| AuthLoggedInAction
| AuthLoggedOutAction
| VerifyCredentialsRequestAction
| VerifyCredentialsSuccessAction
| VerifyCredentialsFailAction
| AuthAccountRememberRequestAction
| AuthAccountRememberSuccessAction
| AuthAccountRememberFailAction;
export {
SWITCH_ACCOUNT,
AUTH_APP_CREATED,
@ -300,4 +384,5 @@ export {
register,
fetchCaptcha,
authLoggedIn,
type AuthAction,
};

View file

@ -39,6 +39,10 @@ const getMeToken = (state: RootState) => {
return state.auth.users.get(accountUrl!)?.access_token;
};
interface MeFetchSkipAction {
type: typeof ME_FETCH_SKIP;
}
const fetchMe = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
@ -46,7 +50,7 @@ const fetchMe = () =>
const accountUrl = getMeUrl(state);
if (!token) {
dispatch({ type: ME_FETCH_SKIP });
dispatch<MeFetchSkipAction>({ type: ME_FETCH_SKIP });
return noOp();
}
@ -122,13 +126,11 @@ interface MePatchSuccessAction {
const patchMeSuccess = (me: CredentialAccount) =>
(dispatch: AppDispatch) => {
const action: MePatchSuccessAction = {
dispatch(importEntities({ accounts: [me] }));
dispatch<MePatchSuccessAction>({
type: ME_PATCH_SUCCESS,
me,
};
dispatch(importEntities({ accounts: [me] }));
dispatch(action);
});
};
const patchMeFail = (error: unknown) => ({
@ -141,6 +143,7 @@ type MeAction =
| ReturnType<typeof fetchMeRequest>
| ReturnType<typeof fetchMeSuccess>
| ReturnType<typeof fetchMeFail>
| MeFetchSkipAction
| ReturnType<typeof patchMeRequest>
| MePatchSuccessAction
| ReturnType<typeof patchMeFail>;

View file

@ -5,11 +5,10 @@
import { produce } from 'immer';
import { VERIFY_CREDENTIALS_SUCCESS, AUTH_ACCOUNT_REMEMBER_SUCCESS } from 'pl-fe/actions/auth';
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS } from 'pl-fe/actions/me';
import { VERIFY_CREDENTIALS_SUCCESS, AUTH_ACCOUNT_REMEMBER_SUCCESS, type AuthAction } from 'pl-fe/actions/auth';
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS, type MeAction } from 'pl-fe/actions/me';
import type { Account, CredentialAccount } from 'pl-api';
import type { AnyAction } from 'redux';
interface AccountMeta {
pleroma: Account['__meta']['pleroma'];
@ -28,7 +27,7 @@ const importAccount = (state: State, account: CredentialAccount): State =>
};
});
const accounts_meta = (state: Readonly<State> = {}, action: AnyAction): State => {
const accounts_meta = (state: Readonly<State> = {}, action: AuthAction | MeAction): State => {
switch (action.type) {
case ME_FETCH_SUCCESS:
case ME_PATCH_SUCCESS:

View file

@ -3,7 +3,7 @@ import trim from 'lodash/trim';
import { applicationSchema, PlApiClient, tokenSchema, type Application, type CredentialAccount, type Token } from 'pl-api';
import * as v from 'valibot';
import { MASTODON_PRELOAD_IMPORT } from 'pl-fe/actions/preload';
import { MASTODON_PRELOAD_IMPORT, type PreloadAction } from 'pl-fe/actions/preload';
import * as BuildConfig from 'pl-fe/build-config';
import KVStore from 'pl-fe/storage/kv-store';
import { validId, isURL, parseBaseURL } from 'pl-fe/utils/auth';
@ -16,8 +16,9 @@ import {
SWITCH_ACCOUNT,
VERIFY_CREDENTIALS_SUCCESS,
VERIFY_CREDENTIALS_FAIL,
type AuthAction,
} from '../actions/auth';
import { ME_FETCH_SKIP } from '../actions/me';
import { ME_FETCH_SKIP, type MeAction } from '../actions/me';
import type { PlfeResponse } from 'pl-fe/api';
import type { Account as AccountEntity } from 'pl-fe/normalizers/account';
@ -278,7 +279,7 @@ const deleteForbiddenToken = (state: State, error: { response: PlfeResponse }, t
}
};
const reducer = (state: State, action: AnyAction) => {
const reducer = (state: State, action: AnyAction | AuthAction | MeAction | PreloadAction) => {
switch (action.type) {
case AUTH_APP_CREATED:
return state.set('app', action.app);

View file

@ -4,7 +4,7 @@ import {
OrderedSet as ImmutableOrderedSet,
} from 'immutable';
import { STATUS_IMPORT, STATUSES_IMPORT } from 'pl-fe/actions/importer';
import { STATUS_IMPORT, STATUSES_IMPORT, type ImporterAction } from 'pl-fe/actions/importer';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from '../actions/accounts';
import {
@ -186,7 +186,7 @@ const deletePendingStatus = (state: State, params: Pick<Status, 'id' | 'in_reply
};
/** Contexts reducer. Used for building a nested tree structure for threads. */
const replies = (state = ReducerRecord(), action: AnyAction | StatusesAction | TimelineAction) => {
const replies = (state = ReducerRecord(), action: AnyAction | ImporterAction | StatusesAction | TimelineAction) => {
switch (action.type) {
case ACCOUNT_BLOCK_SUCCESS:
case ACCOUNT_MUTE_SUCCESS:

View file

@ -2,17 +2,18 @@ import {
AUTH_LOGGED_OUT,
AUTH_ACCOUNT_REMEMBER_SUCCESS,
VERIFY_CREDENTIALS_SUCCESS,
type AuthAction,
} from '../actions/auth';
import {
ME_FETCH_SUCCESS,
ME_FETCH_FAIL,
ME_FETCH_SKIP,
ME_PATCH_SUCCESS,
type MeAction,
} from '../actions/me';
import type { PlfeResponse } from 'pl-fe/api';
import type { Me } from 'pl-fe/types/pl-fe';
import type { AnyAction } from 'redux';
const initialState: Me = null;
@ -24,7 +25,7 @@ const handleForbidden = (state: Me, error: { response: PlfeResponse }) => {
}
};
const me = (state: Me = initialState, action: AnyAction): Me => {
const me = (state: Me = initialState, action: AuthAction | MeAction): Me => {
switch (action.type) {
case ME_FETCH_SUCCESS:
case ME_PATCH_SUCCESS:
@ -36,7 +37,7 @@ const me = (state: Me = initialState, action: AnyAction): Me => {
case AUTH_LOGGED_OUT:
return false;
case ME_FETCH_FAIL:
return handleForbidden(state, action.error);
return handleForbidden(state, action.error as any);
default:
return state;
}

View file

@ -25,7 +25,7 @@ import {
NOTIFICATIONS_MARK_READ_REQUEST,
MAX_QUEUED_NOTIFICATIONS,
} from '../actions/notifications';
import { TIMELINE_DELETE } from '../actions/timelines';
import { TIMELINE_DELETE, type TimelineAction } from '../actions/timelines';
import type { AccountWarning, Notification as BaseNotification, Markers, PaginatedResponse, Relationship, RelationshipSeveranceEvent, Report } from 'pl-api';
import type { Notification } from 'pl-fe/normalizers/notification';
@ -215,7 +215,7 @@ const importMarker = (state: State, marker: Markers) => {
});
};
const notifications = (state: State = ReducerRecord(), action: AnyAction) => {
const notifications = (state: State = ReducerRecord(), action: AnyAction | TimelineAction) => {
switch (action.type) {
case NOTIFICATIONS_EXPAND_REQUEST:
return state.set('isLoading', true);

View file

@ -1,9 +1,8 @@
import { Map as ImmutableMap } from 'immutable';
import { POLLS_IMPORT } from 'pl-fe/actions/importer';
import { POLLS_IMPORT, type ImporterAction } from 'pl-fe/actions/importer';
import type { Poll, Status } from 'pl-api';
import type { AnyAction } from 'redux';
type State = ImmutableMap<string, Poll>;
@ -14,7 +13,7 @@ const importPolls = (state: State, polls: Array<Exclude<Status['poll'], null>>)
const initialState: State = ImmutableMap();
const polls = (state: State = initialState, action: AnyAction): State => {
const polls = (state: State = initialState, action: ImporterAction): State => {
switch (action.type) {
case POLLS_IMPORT:
return importPolls(state, action.polls);

View file

@ -1,6 +1,6 @@
import { Map as ImmutableMap } from 'immutable';
import { STATUS_IMPORT, STATUSES_IMPORT } from 'pl-fe/actions/importer';
import { STATUS_IMPORT, STATUSES_IMPORT, type ImporterAction } from 'pl-fe/actions/importer';
import {
SCHEDULED_STATUSES_FETCH_SUCCESS,
SCHEDULED_STATUS_CANCEL_REQUEST,
@ -25,7 +25,7 @@ const importStatuses = (state: State, statuses: Array<Status | ScheduledStatus>)
const deleteStatus = (state: State, statusId: string) => state.delete(statusId);
const scheduled_statuses = (state: State = initialState, action: AnyAction) => {
const scheduled_statuses = (state: State = initialState, action: AnyAction | ImporterAction) => {
switch (action.type) {
case STATUS_IMPORT:
case STATUS_CREATE_SUCCESS:

View file

@ -31,6 +31,7 @@ import {
JOINED_EVENTS_FETCH_REQUEST,
JOINED_EVENTS_FETCH_SUCCESS,
JOINED_EVENTS_FETCH_FAIL,
type EventsAction,
} from '../actions/events';
import {
FAVOURITED_STATUSES_FETCH_REQUEST,
@ -152,7 +153,7 @@ const removeBookmarkFromLists = (state: State, status: Pick<Status, 'id' | 'book
return state;
};
const statusLists = (state = initialState, action: AnyAction | BookmarksAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusQuotesAction) => {
const statusLists = (state = initialState, action: AnyAction | BookmarksAction | EventsAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusQuotesAction) => {
switch (action.type) {
case FAVOURITED_STATUSES_FETCH_REQUEST:
case FAVOURITED_STATUSES_EXPAND_REQUEST:

View file

@ -1,7 +1,7 @@
import { Record as ImmutableRecord } from 'immutable';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'pl-fe/actions/accounts';
import { DOMAIN_BLOCK_SUCCESS } from 'pl-fe/actions/domain-blocks';
import { DOMAIN_BLOCK_SUCCESS, type DomainBlocksAction } from 'pl-fe/actions/domain-blocks';
import {
SUGGESTIONS_FETCH_REQUEST,
SUGGESTIONS_FETCH_SUCCESS,
@ -37,7 +37,7 @@ const dismissAccount = (state: State, accountId: string) =>
const dismissAccounts = (state: State, accountIds: string[]) =>
state.update('items', items => items.filter(item => !accountIds.includes(item.account_id)));
const suggestionsReducer = (state: State = ReducerRecord(), action: AnyAction) => {
const suggestionsReducer = (state: State = ReducerRecord(), action: AnyAction | DomainBlocksAction) => {
switch (action.type) {
case SUGGESTIONS_FETCH_REQUEST:
return state.set('isLoading', true);

View file

@ -7,8 +7,8 @@ import {
import sample from 'lodash/sample';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from '../actions/accounts';
import { PIN_SUCCESS, UNPIN_SUCCESS } from '../actions/interactions';
import { STATUS_CREATE_REQUEST, STATUS_CREATE_SUCCESS } from '../actions/statuses';
import { PIN_SUCCESS, UNPIN_SUCCESS, type InteractionsAction } from '../actions/interactions';
import { STATUS_CREATE_REQUEST, STATUS_CREATE_SUCCESS, type StatusesAction } from '../actions/statuses';
import {
TIMELINE_UPDATE,
TIMELINE_DELETE,
@ -21,6 +21,7 @@ import {
MAX_QUEUED_ITEMS,
TIMELINE_SCROLL_TOP,
TIMELINE_INSERT,
type TimelineAction,
} from '../actions/timelines';
import type { PaginatedResponse, Status as BaseStatus, Relationship } from 'pl-api';
@ -294,7 +295,7 @@ const handleExpandFail = (state: State, timelineId: string) => state.withMutatio
setFailed(state, timelineId, true);
});
const timelines = (state: State = initialState, action: AnyAction) => {
const timelines = (state: State = initialState, action: AnyAction | InteractionsAction | StatusesAction | TimelineAction) => {
switch (action.type) {
case STATUS_CREATE_REQUEST:
if (action.params.scheduled_at) return state;