Enable the @typescript-eslint/no-explicit-any eslint rule (#1830)

## Description:

Enable the `@typescript-eslint/no-explicit-any` eslint rule.

Fixes #1789

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
This commit is contained in:
Scott Anderson
2025-08-15 21:25:02 -04:00
committed by GitHub
parent 69fcfe7716
commit ef51adda6c
16 changed files with 49 additions and 15 deletions
+12
View File
@@ -75,6 +75,7 @@ export default [
"type",
],
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-mixed-enums": "error",
"@typescript-eslint/no-require-imports": "error",
@@ -127,9 +128,20 @@ export default [
files: [
"**/*.config.{js,ts,jsx,tsx}",
"**/*.test.{js,ts,jsx,tsx}",
"tests/**/*.{js,ts,jsx,tsx}",
],
rules: {
// Disabled rules for tests, configs
"@typescript-eslint/no-explicit-any": "off",
"sort-keys": "off",
},
},
{
files: [
"src/client/**/*.{js,ts,jsx,tsx}",
],
rules: {
// Disabled rules for frontend
"sort-keys": "off",
},
},
+8
View File
@@ -36,12 +36,14 @@ export class LangSelector extends LitElement {
@state() public translations: Record<string, string> | undefined;
@state() public defaultTranslations: Record<string, string> | undefined;
@state() public currentLang = "en";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@state() private languageList: any[] = [];
@state() private showModal = false;
@state() private debugMode = false;
private debugKeyPressed = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private languageMap: Record<string, any> = {
ar,
bg,
@@ -130,6 +132,7 @@ export class LangSelector extends LitElement {
private async loadLanguageList() {
try {
const data = this.languageMap;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let list: any[] = [];
const browserLang = new Intl.Locale(navigator.language).language;
@@ -146,6 +149,7 @@ export class LangSelector extends LitElement {
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let debugLang: any = null;
if (this.debugKeyPressed) {
debugLang = {
@@ -177,6 +181,7 @@ export class LangSelector extends LitElement {
list.sort((a, b) => a.en.localeCompare(b.en));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const finalList: any[] = [];
if (currentLangEntry) finalList.push(currentLangEntry);
if (englishEntry) finalList.push(englishEntry);
@@ -236,7 +241,9 @@ export class LangSelector extends LitElement {
components.forEach((tag) => {
document.querySelectorAll(tag).forEach((el) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (typeof (el as any).requestUpdate === "function") {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(el as any).requestUpdate();
}
});
@@ -317,6 +324,7 @@ export class LangSelector extends LitElement {
}
function flattenTranslations(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
obj: Record<string, any>,
parentKey = "",
result: Record<string, string> = {},
+1
View File
@@ -5,6 +5,7 @@ import { translateText } from "../client/Utils";
@customElement("language-modal")
export class LanguageModal extends LitElement {
@property({ type: Boolean }) visible = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@property({ type: Array }) languageList: any[] = [];
@property({ type: String }) currentLang = "en";
+1
View File
@@ -56,6 +56,7 @@ declare global {
spaAddAds: (ads: Array<{ type: string; selectorId: string }>) => void;
destroyUnits: (adType: string) => void;
settings?: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
slots?: any;
};
spaNewPage: (url: string) => void;
+2
View File
@@ -57,6 +57,7 @@ export function generateCryptoRandomUUID(): string {
// Fallback using crypto.getRandomValues
if (crypto !== undefined && "getRandomValues" in crypto) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (([1e7] as any) + -1e3 + -4e3 + -8e3 + -1e11).replace(
/[018]/g,
(c: number): string =>
@@ -83,6 +84,7 @@ export const translateText = (
key: string,
params: Record<string, string | number> = {},
): string => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const self = translateText as any;
self.formatterCache ??= new Map();
self.lastLang ??= null;
+2 -2
View File
@@ -1,4 +1,4 @@
import { html, LitElement } from "lit";
import { html, LitElement, TemplateResult } from "lit";
import { customElement, state } from "lit/decorators.js";
import { DirectiveResult } from "lit/directive.js";
import { unsafeHTML, UnsafeHTMLDirective } from "lit/directives/unsafe-html.js";
@@ -96,7 +96,7 @@ export class EventsDisplay extends LitElement implements Layer {
]);
private renderButton(options: {
content: any; // Can be string, TemplateResult, or other renderable content
content: string | TemplateResult | DirectiveResult<typeof UnsafeHTMLDirective>;
onClick?: () => void;
className?: string;
disabled?: boolean;
@@ -97,8 +97,8 @@ export class PlayerActionHandler {
this.eventBus.emit(new SendEmojiIntentEvent(targetPlayer, emojiIndex));
}
handleQuickChat(recipient: PlayerView, chatKey: string, params: any = {}) {
this.eventBus.emit(new SendQuickChatEvent(recipient, chatKey, params));
handleQuickChat(recipient: PlayerView, chatKey: string, target?: PlayerID) {
this.eventBus.emit(new SendQuickChatEvent(recipient, chatKey, target));
}
handleDeleteUnit(unitId: number) {
+13 -9
View File
@@ -266,7 +266,7 @@ export class RadialMenu implements Layer {
menuGroup.style("opacity", 0).style("transform", "scale(0.5)");
}
this.menuGroups.set(level, menuGroup as any);
this.menuGroups.set(level, menuGroup);
const offset = -Math.PI / items.length;
@@ -307,7 +307,7 @@ export class RadialMenu implements Layer {
SVGGElement,
unknown
>,
arc: d3.Arc<any, d3.PieArcDatum<MenuElement>>,
arc: d3.Arc<unknown, d3.PieArcDatum<MenuElement>>,
level: number,
) {
arcs
@@ -348,7 +348,7 @@ export class RadialMenu implements Layer {
arcs.each((d) => {
const pathId = d.data.id;
const path = d3.select(`path[data-id="${pathId}"]`);
this.menuPaths.set(pathId, path as any);
this.menuPaths.set(pathId, path as never);
if (
pathId === this.selectedItemId &&
@@ -388,7 +388,9 @@ export class RadialMenu implements Layer {
>,
level: number,
) {
const onHover = (d: d3.PieArcDatum<MenuElement>, path: any) => {
const onHover = (d: d3.PieArcDatum<MenuElement>, path: d3.Selection<
d3.BaseType, unknown, HTMLElement, unknown
>) => {
const disabled = this.params === null || d.data.disabled(this.params);
if (d.data.tooltipItems && d.data.tooltipItems.length > 0) {
this.showTooltip(d.data.tooltipItems);
@@ -407,7 +409,9 @@ export class RadialMenu implements Layer {
path.attr("stroke-width", "3");
};
const onMouseOut = (d: d3.PieArcDatum<MenuElement>, path: any) => {
const onMouseOut = (d: d3.PieArcDatum<MenuElement>, path: d3.Selection<
d3.BaseType, unknown, HTMLElement, unknown
>) => {
const disabled = this.params === null || d.data.disabled(this.params);
if (this.submenuHoverTimeout !== null) {
window.clearTimeout(this.submenuHoverTimeout);
@@ -518,7 +522,7 @@ export class RadialMenu implements Layer {
SVGGElement,
unknown
>,
arc: d3.Arc<any, d3.PieArcDatum<MenuElement>>,
arc: d3.Arc<unknown, d3.PieArcDatum<MenuElement>>,
) {
arcs
.append("g")
@@ -553,7 +557,7 @@ export class RadialMenu implements Layer {
.attr("opacity", disabled ? 0.5 : 1);
}
this.menuIcons.set(contentId, content as any);
this.menuIcons.set(contentId, content as never);
});
}
@@ -735,8 +739,8 @@ export class RadialMenu implements Layer {
});
}
private animateExistingMenu(
previousMenu: d3.Selection<any, unknown, null, undefined>,
private animateExistingMenu<T extends d3.BaseType>(
previousMenu: d3.Selection<T, unknown, null, undefined>,
) {
previousMenu
.transition()
+1
View File
@@ -1,6 +1,7 @@
export type GameEvent = object;
export type EventConstructor<T extends GameEvent = GameEvent> = new (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...args: any[]
) => T;
+1
View File
@@ -285,6 +285,7 @@ export const flattenedEmojiTable: string[] = emojiTable.flat();
/**
* JSON.stringify replacer function that converts bigint values to strings.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function replacer(_key: string, value: any): any {
return typeof value === "bigint" ? value.toString() : value;
}
+1 -1
View File
@@ -13,7 +13,7 @@ import {
WorkerMessage,
} from "./WorkerMessages";
const ctx: Worker = self as any;
const ctx: Worker = self as unknown as Worker;
let gameRunner: Promise<GameRunner> | null = null;
const mapLoader = new FetchGameMapLoader(`/maps`, version);
+1
View File
@@ -64,6 +64,7 @@ export class Cloudflare {
private async makeRequest<T>(
url: string,
method = "GET",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data?: any,
): Promise<T> {
const response = await fetch(url, {
+1
View File
@@ -226,6 +226,7 @@ export class GameServer {
);
});
client.ws.on("error", (error: Error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((error as any).code === "WS_ERR_UNEXPECTED_RSV_1") {
client.ws.close(1002, "WS_ERR_UNEXPECTED_RSV_1");
}
+1
View File
@@ -121,6 +121,7 @@ export async function startMaster() {
// Handle worker crashes
cluster.on("exit", (worker, code, signal) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const workerId = (worker as any).process?.env?.WORKER_ID;
if (!workerId) {
log.error(`worker crashed could not find id`);
+1
View File
@@ -309,6 +309,7 @@ export async function startWorker() {
);
ws.on("error", (error: Error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((error as any).code === "WS_ERR_UNEXPECTED_RSV_1") {
ws.close(1002, "WS_ERR_UNEXPECTED_RSV_1");
}
@@ -102,7 +102,7 @@ export async function postJoinMessageHandler(
break;
}
default: {
log.warn(`Unknown message type: ${(clientMsg as any).type}`, {
log.warn(`Unknown message type: ${clientMsg.type}`, {
clientID: client.clientID,
});
break;