Enable the @typescript-eslint/no-unsafe-assignment eslint rule (#1832)

## Description:

Enable the `@typescript-eslint/no-unsafe-assignment` eslint rule.

Fixes #1781

## 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:57:25 -04:00
committed by GitHub
parent 356364d200
commit 2dfd39f316
12 changed files with 20 additions and 34 deletions
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
export default {
create(context) {
return {
+2 -1
View File
@@ -88,7 +88,7 @@ export default [
"indent": "off", // @stylistic/ts/indent
"sort-keys": "error",
"@typescript-eslint/no-unsafe-argument": "error",
// "@typescript-eslint/no-unsafe-assignment": "error", // TODO: Enable this rule, https://github.com/openfrontio/OpenFrontIO/issues/1781
"@typescript-eslint/no-unsafe-assignment": "error",
// "@typescript-eslint/no-unsafe-member-access": "error", // TODO: Enable this rule, https://github.com/openfrontio/OpenFrontIO/issues/1783
// "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], // TODO: Enable this rule, https://github.com/openfrontio/OpenFrontIO/issues/1784
"@typescript-eslint/no-unused-vars": "off",
@@ -134,6 +134,7 @@ export default [
// Disabled rules for tests, configs
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"sort-keys": "off",
},
},
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { LitElement, html } from "lit";
import { customElement, state } from "lit/decorators.js";
import "./LanguageModal";
+2 -12
View File
@@ -182,16 +182,6 @@ export class UserSettingModal extends LitElement {
}
}
private sliderTroopRatio(e: CustomEvent<{ value: number }>) {
const value = e.detail?.value;
if (typeof value === "number") {
const ratio = value / 100;
localStorage.setItem("settings.troopRatio", ratio.toString());
} else {
console.warn("Slider event missing detail.value", e);
}
}
private toggleTerritoryPatterns(e: CustomEvent<{ checked: boolean }>) {
const enabled = e.detail?.checked;
if (typeof enabled !== "boolean") return;
@@ -389,7 +379,7 @@ export class UserSettingModal extends LitElement {
max="100"
value="40"
easter="true"
@change=${(e: CustomEvent) => {
@change=${(e: CustomEvent<{ value: unknown }>) => {
const value = e.detail?.value;
if (value !== undefined) {
console.log("Changed:", value);
@@ -408,7 +398,7 @@ export class UserSettingModal extends LitElement {
min="0"
max="1000"
easter="true"
@change=${(e: CustomEvent) => {
@change=${(e: CustomEvent<{ value: unknown }>) => {
const value = e.detail?.value;
if (value !== undefined) {
console.log("Changed:", value);
+2 -1
View File
@@ -84,7 +84,7 @@ export const translateText = (
key: string,
params: Record<string, string | number> = {},
): string => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
const self = translateText as any;
self.formatterCache ??= new Map();
self.lastLang ??= null;
@@ -124,6 +124,7 @@ export const translateText = (
? "en"
: langSelector.currentLang;
const cacheKey = `${key}:${locale}:${message}`;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
let formatter = self.formatterCache.get(cacheKey);
if (!formatter) {
@@ -28,17 +28,6 @@ export class SettingSlider extends LitElement {
);
}
private handleSliderChange(e: Event) {
const detail = (e as CustomEvent)?.detail;
if (!detail || detail.value === undefined) {
console.warn("Invalid slider change event", e);
return;
}
const value = detail.value;
console.log("Slider changed to", value);
}
private updateSliderStyle(slider: HTMLInputElement) {
const percent = ((this.value - this.min) / (this.max - this.min)) * 100;
slider.style.background = `linear-gradient(to right, #2196f3 ${percent}%, #444 ${percent}%)`;
+4 -4
View File
@@ -81,9 +81,9 @@ export function createGrid(
const width = scaledBoundingBox.max.x - scaledBoundingBox.min.x + 1;
const height = scaledBoundingBox.max.y - scaledBoundingBox.min.y + 1;
const grid: boolean[][] = Array(width)
.fill(null)
.map(() => Array(height).fill(false));
const grid: boolean[][] = Array<Array<boolean>>(width)
.fill(null as unknown as boolean[])
.map(() => Array<boolean>(height).fill(false));
for (let x = scaledBoundingBox.min.x; x <= scaledBoundingBox.max.x; x++) {
for (let y = scaledBoundingBox.min.y; y <= scaledBoundingBox.max.y; y++) {
@@ -102,7 +102,7 @@ export function createGrid(
export function findLargestInscribedRectangle(grid: boolean[][]): Rectangle {
const rows = grid[0].length;
const cols = grid.length;
const heights: number[] = new Array(cols).fill(0);
const heights: number[] = new Array<number>(cols).fill(0);
let largestRect: Rectangle = { x: 0, y: 0, width: 0, height: 0 };
for (let row = 0; row < rows; row++) {
+1 -1
View File
@@ -297,7 +297,7 @@ export class FakeHumanExecution implements Execution {
UnitType.SAMLauncher,
);
const structureTiles = structures.map((u) => u.tile());
const randomTiles: (TileRef | null)[] = new Array(10);
const randomTiles: (TileRef | null)[] = new Array<TileRef | null>(10).fill(null);
for (let i = 0; i < randomTiles.length; i++) {
randomTiles[i] = this.randTerritoryTile(other);
}
+3 -3
View File
@@ -92,9 +92,9 @@ export class GameMapImpl implements GameMap {
this.state = new Uint16Array(width * height);
// Precompute the LUTs
let ref = 0;
this.refToX = new Array(width * height);
this.refToY = new Array(width * height);
this.yToRef = new Array(height);
this.refToX = new Array<number>(width * height);
this.refToY = new Array<number>(width * height);
this.yToRef = new Array<TileRef>(height);
for (let y = 0; y < height; y++) {
this.yToRef[y] = ref;
for (let x = 0; x < width; x++) {
+1
View File
@@ -66,6 +66,7 @@ async function getGatekeeper(): Promise<Gatekeeper> {
// Use dynamic import for ES modules
// Using a type assertion to avoid TypeScript errors for optional modules
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const module = await import(
"./gatekeeper/RealGatekeeper.js" as string
).catch(() => import("./gatekeeper/RealGatekeeper.js" as string));
+3 -1
View File
@@ -91,6 +91,7 @@ export async function startMaster() {
cluster.on("message", (worker, message) => {
if (message.type === "WORKER_READY") {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const workerId = message.workerId;
readyWorkers.add(workerId);
log.info(
@@ -121,7 +122,7 @@ export async function startMaster() {
// Handle worker crashes
cluster.on("exit", (worker, code, signal) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
const workerId = (worker as any).process?.env?.WORKER_ID;
if (!workerId) {
log.error(`worker crashed could not find id`);
@@ -135,6 +136,7 @@ export async function startMaster() {
// Restart the worker with the same ID
const newWorker = cluster.fork({
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
WORKER_ID: workerId,
});
View File