[dev] More stylistic eslint rules (#5961)

This commit is contained in:
zubiden 2025-06-04 20:41:03 +02:00 committed by Alexander Zinchuk
parent ee7f2e1c8c
commit bd096e2a01
56 changed files with 120 additions and 138 deletions

View File

@ -16,6 +16,7 @@ import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
tseslint.configs.stylistic,
reactPlugin.configs.flat.recommended,
reactXPlugin.configs['recommended-type-checked'],
jsxA11yPlugin.flatConfigs.recommended,
@ -51,6 +52,20 @@ export default tseslint.config(
rules: {
'no-null/no-null': 'error',
'no-console': 'error',
'no-template-curly-in-string': 'error',
'object-shorthand': 'error',
curly: ['error', 'multi-line'],
'no-implicit-coercion': [
'error',
{
boolean: true,
disallowTemplateShorthand: true,
},
],
'no-prototype-builtins': 'off',
'no-undef': 'off',
'no-unused-vars': 'off',
'@stylistic/multiline-ternary': 'off',
'@stylistic/max-len': ['error', {
code: 120,
ignoreComments: true,
@ -60,10 +75,6 @@ export default tseslint.config(
SwitchCase: 1,
flatTernaryExpressions: false,
}],
'@stylistic/multiline-ternary': 'off',
'no-prototype-builtins': 'off',
'no-undef': 'off',
'no-unused-vars': 'off',
'simple-import-sort/imports': [
'error',
{
@ -115,7 +126,6 @@ export default tseslint.config(
],
},
],
// TypeScript type imports preference
'@typescript-eslint/consistent-type-imports': [
'error',
{
@ -130,6 +140,11 @@ export default tseslint.config(
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/prefer-for-of': 'off',
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/no-misused-promises': [
'error',
{
@ -169,6 +184,15 @@ export default tseslint.config(
'react/no-unknown-property': 'off',
'react/display-name': 'off',
'react/jsx-key': 'off',
'react/jsx-curly-spacing': [
'error',
{
when: 'never',
attributes: true,
children: true,
allowMultiline: true,
},
],
'react-x/no-use-context': 'off',
'react-x/no-context-provider': 'off',
'react-x/no-array-index-key': 'off',

View File

@ -3,7 +3,7 @@ import { devices, type PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: 'tests/playwright',
timeout: process.env.CI ? 60 * 5 * 1000 : 30 * 1000,
forbidOnly: !!process.env.CI,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
webServer: {
command: 'npm run build:mocked && serve -l 1235 dist',

View File

@ -86,7 +86,7 @@ import { handleGramJsUpdate, invokeRequest, uploadFile } from './client';
type FullChatData = {
fullInfo: ApiChatFullInfo;
chats: ApiChat[];
userStatusesById: { [userId: string]: ApiUserStatus };
userStatusesById: Record<string, ApiUserStatus>;
groupCall?: Partial<ApiGroupCall>;
membersCount?: number;
isForumAsMessages?: true;

View File

@ -18,7 +18,7 @@ import * as cacheApi from '../../../util/cacheApi';
import { getEntityTypeById } from '../gramjsBuilders';
import localDb from '../localDb';
const MEDIA_ENTITY_TYPES: Set<EntityType> = new Set([
const MEDIA_ENTITY_TYPES = new Set<EntityType>([
'sticker', 'wallpaper', 'photo', 'webDocument', 'document',
]);

View File

@ -2114,7 +2114,7 @@ export async function fetchOutboxReadDate({ chat, messageId }: { chat: ApiChat;
const peer = buildInputPeer(id, accessHash);
const result = await invokeRequest(new GramJs.messages.GetOutboxReadDate({
peer: peer,
peer,
msgId: messageId,
}), { shouldThrow: true });

View File

@ -184,7 +184,7 @@ export function callApiLocal<T extends keyof Methods>(
| (Api.VirtualClass<any> | undefined)[];
type ForbiddenResponses =
ForbiddenTypes
| (AnyLiteral & { [k: string]: ForbiddenTypes });
| (AnyLiteral & Record<string, ForbiddenTypes>);
// Unwrap all chained promises
const response = await promise;
@ -231,7 +231,7 @@ export function callApi<T extends keyof Methods>(fnName: T, ...args: MethodArgs<
| (Api.VirtualClass<any> | undefined)[];
type ForbiddenResponses =
ForbiddenTypes
| (AnyLiteral & { [k: string]: ForbiddenTypes });
| (AnyLiteral & Record<string, ForbiddenTypes>);
// Unwrap all chained promises
const response = await promise;
@ -346,7 +346,7 @@ function makeRequestToMaster(message: {
const requestState = { messageId } as RequestState;
// Re-wrap type because of `postMessage`
const promise: Promise<MethodResponse<keyof Methods>> = new Promise((resolve, reject) => {
const promise = new Promise<MethodResponse<keyof Methods>>((resolve, reject) => {
Object.assign(requestState, { resolve, reject });
});
@ -385,7 +385,7 @@ function makeRequest(message: OriginPayload) {
const requestState = { messageId } as RequestState;
// Re-wrap type because of `postMessage`
const promise: Promise<MethodResponse<keyof Methods>> = new Promise((resolve, reject) => {
const promise = new Promise<MethodResponse<keyof Methods>>((resolve, reject) => {
Object.assign(requestState, { resolve, reject });
});

View File

@ -855,9 +855,7 @@ export type ApiReplyKeyboard = {
keyboardPlaceholder?: string;
isKeyboardSingleUse?: boolean;
isKeyboardSelective?: boolean;
} & {
[K in 'inlineButtons' | 'keyboardButtons']?: ApiKeyboardButtons;
};
} & Partial<Record<'inlineButtons' | 'keyboardButtons', ApiKeyboardButtons>>;
export type ApiTranscription = {
text: string;

View File

@ -266,13 +266,11 @@ export interface ApiConfig {
export type ApiPeerColorSet = string[];
export interface ApiPeerColors {
general: {
[key: number]: {
isHidden?: true;
colors?: ApiPeerColorSet;
darkColors?: ApiPeerColorSet;
};
};
general: Record<number, {
isHidden?: true;
colors?: ApiPeerColorSet;
darkColors?: ApiPeerColorSet;
}>;
generalHash?: number;
}

View File

@ -65,7 +65,6 @@ function AnimatedIconWithPreview(props: OwnProps) {
onLoad={handlePreviewLoad}
/>
)}
{ }
<AnimatedIcon {...otherProps} onLoad={handleAnimationReady} />
</div>
);

View File

@ -364,7 +364,7 @@ const Audio: FC<OwnProps> = ({
{withSeekline && (
<div className="meta search-result" dir={isRtl ? 'rtl' : undefined}>
<span className="duration with-seekline" dir="auto">
{playProgress < 1 && `${formatMediaDuration(duration * playProgress, duration)}`}
{playProgress < 1 && formatMediaDuration(duration * playProgress, duration)}
</span>
{renderSeekline(playProgress, bufferedRanges, seekerRef)}
</div>

View File

@ -312,7 +312,7 @@ const CalendarModal: FC<OwnProps> = ({
currentYear, currentMonth, gridDate, minDate, maxDate,
)
? 'disabled'
: `${gridDate ? 'clickable' : ''}`,
: gridDate ? 'clickable' : '',
selectedDay === formatDay(currentYear, currentMonth, gridDate) && 'selected',
)}
>

View File

@ -136,7 +136,7 @@ const DeleteMessageModal: FC<OwnProps & StateProps> = ({
const buildNestedOptionListWithAvatars = useLastCallback(() => {
return peerList.map((member) => {
return {
value: `${member.id}`,
value: member.id,
label: getPeerTitle(lang, member) || '',
leftElement: <Avatar size="small" peer={member} />,
};

View File

@ -291,7 +291,7 @@ const StickerButton = <T extends number | ApiSticker | ApiBotInlineMediaResult |
onClick={handleClick}
onContextMenu={handleContextMenu}
>
{withSparkles && <Sparkles preset="button" /> }
{withSparkles && <Sparkles preset="button" />}
{isIntesectingForShowing && (
<StickerView
containerRef={ref}

View File

@ -356,7 +356,7 @@ export function insertTextEntity(entities: ApiMessageEntity[], newEntity: ApiMes
// Organize entities in a tree-like structure to better represent how the text will be displayed
function organizeEntities(entities: ApiMessageEntity[]) {
const organizedEntityIndexes: Set<number> = new Set();
const organizedEntityIndexes = new Set<number>();
const organizedEntities: IOrganizedEntity[] = [];
entities.forEach((entity, index) => {

View File

@ -83,7 +83,7 @@ export default function useAnimatedEmoji(
const { x, y } = container.getBoundingClientRect();
interactWithAnimatedEmoji({
emoji: emoji,
emoji,
x,
y,
startSize: size,

View File

@ -245,12 +245,14 @@ const PeerPicker = <CategoryType extends string = CustomPeerType>({
const peerOrCategory = peer || category;
if (!peerOrCategory) {
if (DEBUG) return (
<div key={id}>
No peer or category with ID
{id}
</div>
);
if (DEBUG) {
return (
<div key={id}>
No peer or category with ID
{id}
</div>
);
}
return undefined;
}

View File

@ -395,7 +395,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
{birthday && (
<UserBirthday key={peerId} birthday={birthday} user={user!} isInSettings={isInSettings} />
)}
{ hasMainMiniApp && (
{hasMainMiniApp && (
<ListItem
multiline
isStatic

View File

@ -16,7 +16,7 @@ type OwnProps = {
containerId?: string;
};
const revealByContainerId: Map<string, VoidFunction[]> = new Map();
const revealByContainerId = new Map<string, VoidFunction[]>();
const buildClassName = createClassNameBuilder('Spoiler');

View File

@ -190,9 +190,9 @@
}
.search-sponsored-badge {
cursor: pointer;
display: flex;
align-self: flex-start;
cursor: pointer;
&:hover {
filter: brightness(1.1);
}

View File

@ -550,7 +550,7 @@ const Main = ({
});
// Online status and browser tab indicators
useBackgroundMode(handleBlur, handleFocus, !!IS_ELECTRON);
useBackgroundMode(handleBlur, handleFocus, Boolean(IS_ELECTRON));
useBeforeUnload(handleBlur);
usePreventPinchZoomGesture(isMediaViewerOpen || isStoryViewerOpen);

View File

@ -103,7 +103,7 @@ const DEFAULT_CUSTOM_EXPIRE_DATE = 86400 * 3 * 1000; // 3 days
const MAX_ADDITIONAL_CHANNELS = 9;
const DEFAULT_BOOST_COUNT = 5;
const GIVEAWAY_IMG_LIST: { [key: number]: string } = {
const GIVEAWAY_IMG_LIST: Partial<Record<number, string>> = {
3: GiftGreenRound,
6: GiftBlueRound,
12: GiftRedRound,
@ -721,7 +721,11 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
{dataStarsPrepaidGiveaway ? (
<img className={styles.prepaidImg} src={GiftStar} alt="" />
) : (
<img className={styles.prepaidImg} src={GIVEAWAY_IMG_LIST[dataPrepaidGiveaway!.months]} alt="" />
<img
className={styles.prepaidImg}
src={GIVEAWAY_IMG_LIST[dataPrepaidGiveaway!.months] || GIVEAWAY_IMG_LIST[3]}
alt=""
/>
)}
</div>
<div className={styles.info}>

View File

@ -37,7 +37,7 @@ const GiveawayTypeOption: FC<OwnProps> = ({
let displayText: string | undefined = lang(text);
if (isLink && selectedMemberIds?.length) {
displayText = selectedMemberIds.length > 2 ? `${selectedMemberIds.length}` : userNames;
displayText = selectedMemberIds.length > 2 ? selectedMemberIds.length.toString() : userNames;
}
const handleChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
@ -70,7 +70,7 @@ const GiveawayTypeOption: FC<OwnProps> = ({
<img className={styles.optionImg} src={img} alt="" draggable={false} />
<div className={styles.giveaway}>
<h3 className={styles.title}>
{lang(`${name}`)}
{lang(name)}
</h3>
{isLink ? (
<div className={styles.link} onClick={handleClick}>

View File

@ -352,14 +352,14 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
return (
<div className={fullClassName}>
{ !isForEffects && (
{!isForEffects && (
<div ref={headerRef} className={headerClassName}>
<div className="shared-canvas-container">
<canvas ref={sharedCanvasRef} className="shared-canvas" />
{allSets.map(renderCover)}
</div>
</div>
) }
)}
<div
ref={containerRef}
onMouseMove={handleMouseMove}

View File

@ -68,7 +68,7 @@ export default async function buildAttachment(
const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);
shouldSendAsFile = !validateAspectRatio(width, height);
if (!shouldSendAsFile) {
quick = { width: width, height: height, duration: duration };
quick = { width, height, duration };
}
} catch (err) {
shouldSendAsFile = true;

View File

@ -89,13 +89,13 @@ type StateProps = {
isAccountFrozen?: boolean;
};
const SINGLE_LINE_ACTIONS: Set<ApiMessageAction['type']> = new Set([
const SINGLE_LINE_ACTIONS = new Set<ApiMessageAction['type']>([
'pinMessage',
'chatEditPhoto',
'chatDeletePhoto',
'unsupported',
]);
const HIDDEN_TEXT_ACTIONS: Set<ApiMessageAction['type']> = new Set(['giftCode', 'prizeStars', 'suggestProfilePhoto']);
const HIDDEN_TEXT_ACTIONS = new Set<ApiMessageAction['type']>(['giftCode', 'prizeStars', 'suggestProfilePhoto']);
const ActionMessage = ({
message,

View File

@ -137,7 +137,7 @@ const CommentButton: FC<OwnProps> = ({
)}
color={isCustomShape ? 'white' : 'blue'}
/>
) }
)}
<Icon
name="next"
className={buildClassName(

View File

@ -70,7 +70,7 @@ export default function withSelectControl(WrappedComponent: FC) {
)}
</div>
)}
{ }
{}
<WrappedComponent {...newProps} />
</div>
);

View File

@ -246,7 +246,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
return !isLimited && !isSoldOut;
}
if (areUnlimitedStarGiftsDisallowed && areLimitedStarGiftsDisallowed) {
return Boolean(isLimited && !!upgradeStars);
return Boolean(isLimited && Boolean(upgradeStars));
}
return true;

View File

@ -342,7 +342,7 @@ const PaidReactionModal = ({
})}
</div>
)}
{topReactors && (<Separator className={styles.separator} />) }
{topReactors && (<Separator className={styles.separator} />)}
<Checkbox
className={buildClassName(styles.checkBox, 'dialog-checkbox')}
checked={!shouldSendAsAnonymous}

View File

@ -87,7 +87,7 @@ const StarPaymentModal = ({
if (paidMediaMessage) {
const extendedMedia = paidMediaMessage.content.paidMedia!.extendedMedia as ApiMediaExtendedPreview[];
const areAllPhotos = extendedMedia.every((media) => !media.duration);
const areAllVideos = extendedMedia.every((media) => !!media.duration);
const areAllVideos = extendedMedia.every((media) => Boolean(media.duration));
const mediaText = areAllPhotos ? oldLang('Stars.Transfer.Photos', extendedMedia.length)
: areAllVideos ? oldLang('Stars.Transfer.Videos', extendedMedia.length)

View File

@ -68,14 +68,14 @@ const MinimizedWebAppModal = ({
function renderTitle() {
const activeTabName = peers.length > 0 && peers[0]?.firstName;
const title = openedTabsCount && activeTabName && openedTabsCount > 1
? `${lang('MiniAppsMoreTabs',
? lang('MiniAppsMoreTabs',
{
botName: activeTabName,
count: openedTabsCount - 1,
},
{
pluralValue: openedTabsCount - 1,
})}`
})
: activeTabName;
return (

View File

@ -713,7 +713,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
modalHeight={currentHeight}
/>
))}
{ isMoreAppsTabActive && (<MoreAppsTabContent />)}
{isMoreAppsTabActive && (<MoreAppsTabContent />)}
</Modal>
);
};

View File

@ -1109,7 +1109,7 @@ const WebAppModalTabContent: FC<OwnProps & StateProps> = ({
{mainButton?.isProgressVisible && <Spinner className={styles.mainButtonSpinner} color="white" />}
</Button>
</div>
) }
)}
{popupParameters && (
<Modal
isOpen={Boolean(popupParameters)}

View File

@ -167,10 +167,10 @@ const ShippingInfo: FC<OwnProps> = ({
/>
</div>
) : undefined}
{ needName || needEmail || needPhone ? (
{needName || needEmail || needPhone ? (
<h5>{oldLang('PaymentShippingReceiver')}</h5>
) : undefined }
{ needName && (
) : undefined}
{needName && (
<InputText
label={oldLang('PaymentShippingName')}
onChange={handleFullNameChange}
@ -179,8 +179,8 @@ const ShippingInfo: FC<OwnProps> = ({
tabIndex={0}
error={formErrors.fullName && lang.withRegular(formErrors.fullName)}
/>
) }
{ needEmail && (
)}
{needEmail && (
<InputText
label={oldLang('PaymentShippingEmailPlaceholder')}
onChange={handleEmailChange}
@ -189,8 +189,8 @@ const ShippingInfo: FC<OwnProps> = ({
tabIndex={0}
error={formErrors.email && lang.withRegular(formErrors.email)}
/>
) }
{ needPhone && (
)}
{needPhone && (
<InputText
label={oldLang('PaymentShippingPhoneNumber')}
onChange={handlePhoneChange}
@ -200,7 +200,7 @@ const ShippingInfo: FC<OwnProps> = ({
error={formErrors.phone && lang.withRegular(formErrors.phone)}
ref={phoneRef}
/>
) }
)}
<Checkbox
label={oldLang('PaymentShippingSave')}
subLabel={oldLang('PaymentShippingSaveInfo')}

View File

@ -782,7 +782,7 @@ const Profile: FC<OwnProps & StateProps> = ({
))}
{!isCurrentUserPremium && (
<>
{ }
{}
<Button className="show-more-channels" size="smaller" onClick={() => openPremiumModal()}>
{oldLang('UnlockSimilar')}
<Icon name="unlock-badge" />
@ -821,7 +821,7 @@ const Profile: FC<OwnProps & StateProps> = ({
))}
{!isCurrentUserPremium && (
<>
{ }
{}
<Button className="show-more-bots" size="smaller" onClick={() => openPremiumModal()}>
{lang('UnlockMoreSimilarBots')}
<Icon name="unlock-badge" />

View File

@ -167,7 +167,7 @@ const ManageBot: FC<OwnProps & StateProps> = ({
});
const handleChangeSettings = useLastCallback(() => {
startBotFatherConversation({ param: `${username}` });
startBotFatherConversation({ param: username! });
});
const inputRef = useRef<HTMLInputElement>();

View File

@ -200,7 +200,7 @@ const ManageChannel: FC<OwnProps & StateProps> = ({
const enabledLength = chatFullInfo.enabledReactions.allowed.length;
const totalLength = availableReactions?.filter((reaction) => !reaction.isInactive).length || 0;
return totalLength ? `${enabledLength} / ${totalLength}` : `${enabledLength}`;
return totalLength ? `${enabledLength} / ${totalLength}` : enabledLength.toString();
}, [availableReactions, chatFullInfo?.enabledReactions, lang]);
const isChannelPublic = useMemo(() => isChatPublic(chat), [chat]);

View File

@ -270,7 +270,7 @@ const ManageGroup: FC<OwnProps & StateProps> = ({
return totalLength
? `${enabledLength} / ${totalLength}`
: `${enabledLength}`;
: enabledLength.toString();
}, [availableReactions, chatFullInfo?.enabledReactions, lang]);
const enabledPermissionsCount = useMemo(() => {

View File

@ -192,7 +192,7 @@ const ManageReactions: FC<OwnProps & StateProps> = ({
return (
<div className="Management">
<div className="panel-content custom-scroll">
{ Boolean(localReactionsLimit && shouldShowReactionsLimit) && (
{Boolean(localReactionsLimit && shouldShowReactionsLimit) && (
<div className="section">
<h3 className="section-heading">
{lang('MaximumReactionsHeader')}

View File

@ -50,7 +50,7 @@ type StateProps = {
isChannel?: boolean;
};
const GIVEAWAY_IMG_LIST: { [key: number]: string } = {
const GIVEAWAY_IMG_LIST: Partial<Record<number, string>> = {
3: GiftGreenRound,
6: GiftBlueRound,
12: GiftRedRound,
@ -319,7 +319,7 @@ const BoostStatistics = ({
/>
) : (
<img
src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]}
src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months] || GIVEAWAY_IMG_LIST[3]}
className={styles.giveawayIcon}
alt={lang('Giveaway')}
/>

View File

@ -13,7 +13,7 @@ const RIBBON_Z_INDEX = 11;
const STROKE_OFFSET = 0.1875 * REM;
const CANVAS_OFFSET = 0.125 * REM;
const callbacks: Set<NoneToVoidFunction> = new Set();
const callbacks = new Set<NoneToVoidFunction>();
export function animateOpening(isArchived?: boolean) {
cancelDelayedCallbacks();
@ -99,7 +99,7 @@ export function animateOpening(isArchived?: boolean) {
applyStyles(ghost, {
top: `${toTop}px`,
left: `${toLeft}px`,
zIndex: `${zIndex}`,
zIndex: String(zIndex),
opacity: ghost2 ? '0' : '',
transform: `translate3d(${fromTranslateX}px, ${fromTranslateY}px, 0) scale(${fromScale})`,
});
@ -108,7 +108,7 @@ export function animateOpening(isArchived?: boolean) {
applyStyles(ghost2, {
top: `${fromTop}px`,
left: `${fromLeft}px`,
zIndex: `${zIndex}`,
zIndex: String(zIndex),
});
}
@ -238,14 +238,14 @@ export function animateClosing(isArchived?: boolean) {
top: `${fromTop}px`,
left: `${fromLeft}px`,
width: `${fromWidth}px`,
zIndex: `${zIndex}`,
zIndex: String(zIndex),
});
if (ghost2) {
applyStyles(ghost2, {
top: `${toTop}px`,
left: `${toLeft}px`,
zIndex: `${zIndex}`,
zIndex: String(zIndex),
opacity: '0',
transform: `translate3d(${fromTranslateX}px, ${fromTranslateY}px, 0) scale(${fromScale})`,
});

View File

@ -1,3 +1,4 @@
/* eslint-disable no-template-curly-in-string */
const config = {
productName: 'Telegram A',
artifactName: '${productName}-${arch}.${ext}',

View File

@ -337,7 +337,7 @@ addActionHandler('queryInlineBot', async (global, actions, payload): Promise<voi
void runDebouncedForSearch(() => {
searchInlineBot(global, {
username,
inlineBotData: inlineBotData,
inlineBotData,
chatId,
query,
offset,

View File

@ -427,7 +427,7 @@ addActionHandler('openThread', async (global, actions, payload): Promise<void> =
if (focusMessageId) {
actions.focusMessage({
chatId,
threadId: threadId,
threadId,
messageId: focusMessageId,
tabId,
});
@ -464,7 +464,7 @@ addActionHandler('openThread', async (global, actions, payload): Promise<void> =
actions.processOpenChatOrThread({
chatId,
type,
threadId: threadId,
threadId,
tabId,
isComments,
noForumTopicPanel,

View File

@ -15,7 +15,7 @@ export default function useEnsureMessage(
useEffect(() => {
if (isDisabled) return;
if (messageId && !message) {
loadMessage({ chatId, messageId: messageId, replyOriginForId: replyOriginForId! });
loadMessage({ chatId, messageId, replyOriginForId: replyOriginForId! });
}
}, [isDisabled, chatId, message, messageId, replyOriginForId]);
}

View File

@ -9,4 +9,4 @@ insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4
indent_size = 2

View File

@ -1,5 +0,0 @@
tl/api.d.ts
tl/apiTl.ts
tl/schemaTl.ts
tl/apiTl.full.ts
tl/schemaTl.full.ts

View File

@ -1,35 +0,0 @@
{
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"root": true,
"rules": {
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"@typescript-eslint/indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"max-len": [
"error",
120
],
"no-bitwise": "off",
"no-underscore-dangle": "off",
"no-continue": "off",
"no-restricted-syntax": "off",
"class-methods-use-this": "off",
"max-classes-per-file": "off",
"camelcase": "off"
},
"ignorePatterns": ["client/mockUtils/*", "client/__invokeMiddlewares__/*"]
}

View File

@ -45,7 +45,7 @@ const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
const FILTERED_ATTRIBUTES = new Set(['key', 'ref', 'teactFastList', 'teactOrderKey']);
const HTML_ATTRIBUTES = new Set(['dir', 'role', 'form']);
const CONTROLLABLE_TAGS = ['INPUT', 'TEXTAREA', 'SELECT'];
const MAPPED_ATTRIBUTES: { [k: string]: string } = {
const MAPPED_ATTRIBUTES: Partial<Record<string, string>> = {
autoCapitalize: 'autocapitalize',
autoComplete: 'autocomplete',
autoCorrect: 'autocorrect',

View File

@ -15,7 +15,7 @@ const connections = launchMediaWorkers();
let videoPreview: VideoPreview | undefined;
export class VideoPreview {
frames: Map<number, ImageBitmap> = new Map();
frames = new Map<number, ImageBitmap>();
currentTime = 0;

View File

@ -61,9 +61,7 @@ export type SharedSessionData = {
date?: number;
dcId: number;
isTest?: true;
} & {
[K in `dc${DcId}_${'auth_key' | 'server_salt'}`]?: string;
} & SessionUserInfo;
} & Partial<Record<`dc${DcId}_${'auth_key' | 'server_salt'}`, string>> & SessionUserInfo;
export type AccountInfo = {
isTest?: true;
@ -103,9 +101,7 @@ export type PerformanceTypeKey = (
| 'animatedEmoji' | 'loopAnimatedStickers' | 'reactionEffects' | 'stickerEffects' | 'autoplayGifs' | 'autoplayVideos'
| 'storyRibbonAnimations' | 'snapEffect'
);
export type PerformanceType = {
[key in PerformanceTypeKey]: boolean;
};
export type PerformanceType = Record<PerformanceTypeKey, boolean>;
export interface IThemeSettings {
background?: string;

View File

@ -140,7 +140,7 @@ class ConnectorClass<T extends InputRequestTypes> {
const requestState = { messageId } as RequestState;
// Re-wrap type because of `postMessage`
const promise: Promise<any> = new Promise((resolve, reject) => {
const promise = new Promise<any>((resolve, reject) => {
Object.assign(requestState, { resolve, reject });
});

View File

@ -6,7 +6,7 @@ import { animate } from './animation';
const DEFAULT_DURATION = 300;
const stopById: Map<string, VoidFunction> = new Map();
const stopById = new Map<string, VoidFunction>();
export default function animateHorizontalScroll(container: HTMLElement, left: number, duration = DEFAULT_DURATION) {
if (!selectCanAnimateInterface(getGlobal())) {

View File

@ -22,7 +22,7 @@ type CustomEmojiInputRenderCallback = (emojiId: string) => void;
const DOM_PROCESS_THROTTLE = 500;
const INPUT_WAITING_CUSTOM_EMOJI_IDS: Set<string> = new Set();
const INPUT_WAITING_CUSTOM_EMOJI_IDS = new Set<string>();
const handlers = new Map<CustomEmojiLoadCallback, string>();
const renderCallbacks = createCallbackManager<CustomEmojiInputRenderCallback>();

View File

@ -4,9 +4,7 @@ type OrderDirection =
'asc'
| 'desc';
interface OrderCallback<T> {
(member: T): any;
}
type OrderCallback<T> = (member: T) => unknown;
export function buildCollectionByKey<T extends AnyLiteral>(collection: T[], key: keyof T) {
return collection.reduce((byKey: CollectionByKey<T>, member: T) => {
@ -82,6 +80,7 @@ export function orderBy<T>(
const aValue = (typeof currentOrderRule === 'function' ? currentOrderRule(a) : a[currentOrderRule]) || 0;
const bValue = (typeof currentOrderRule === 'function' ? currentOrderRule(b) : b[currentOrderRule]) || 0;
// @ts-expect-error Rely on the JS to handle the comparison
return isAsc ? aValue - bValue : bValue - aValue;
}

View File

@ -15,6 +15,7 @@
"strict": true,
"forceConsistentCasingInFileNames": true,
"allowImportingTsExtensions": true,
"noImplicitReturns": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,