fix: replace explicit any types with proper TypeScript types

- Replace 'any' with 'unknown' in catch blocks and add type assertions
- Create explicit interfaces for complex objects (HostConfig, TabData, TerminalHandle)
- Fix window/document object type extensions
- Update Electron API type definitions
- Improve type safety in database routes and utilities
- Add proper types to Terminal components (Desktop & Mobile)
- Fix navigation component types (TopNavbar, LeftSidebar, AppView)

Reduces TypeScript lint errors from 394 to 358 (-36 errors)
Fixes 45 @typescript-eslint/no-explicit-any violations
This commit is contained in:
ZacharyZcR
2025-10-09 18:06:17 +08:00
parent 1decac481e
commit d7e98cda04
22 changed files with 2002 additions and 1540 deletions

View File

@@ -12,7 +12,7 @@ class DataCrypto {
static encryptRecord(
tableName: string,
record: any,
record: Record<string, unknown>,
userId: string,
userDataKey: Buffer,
): any {
@@ -24,7 +24,7 @@ class DataCrypto {
encryptedRecord[fieldName] = FieldCrypto.encryptField(
value as string,
userDataKey,
recordId,
recordId as string,
fieldName,
);
}
@@ -35,7 +35,7 @@ class DataCrypto {
static decryptRecord(
tableName: string,
record: any,
record: Record<string, unknown>,
userId: string,
userDataKey: Buffer,
): any {
@@ -49,7 +49,7 @@ class DataCrypto {
decryptedRecord[fieldName] = LazyFieldEncryption.safeGetFieldValue(
value as string,
userDataKey,
recordId,
recordId as string,
fieldName,
);
}
@@ -60,13 +60,18 @@ class DataCrypto {
static decryptRecords(
tableName: string,
records: any[],
records: unknown[],
userId: string,
userDataKey: Buffer,
): any[] {
): unknown[] {
if (!Array.isArray(records)) return records;
return records.map((record) =>
this.decryptRecord(tableName, record, userId, userDataKey),
this.decryptRecord(
tableName,
record as Record<string, unknown>,
userId,
userDataKey,
),
);
}
@@ -386,7 +391,7 @@ class DataCrypto {
static encryptRecordForUser(
tableName: string,
record: any,
record: Record<string, unknown>,
userId: string,
): any {
const userDataKey = this.validateUserAccess(userId);
@@ -395,7 +400,7 @@ class DataCrypto {
static decryptRecordForUser(
tableName: string,
record: any,
record: Record<string, unknown>,
userId: string,
): any {
const userDataKey = this.validateUserAccess(userId);
@@ -404,9 +409,9 @@ class DataCrypto {
static decryptRecordsForUser(
tableName: string,
records: any[],
records: unknown[],
userId: string,
): any[] {
): unknown[] {
const userDataKey = this.validateUserAccess(userId);
return this.decryptRecords(tableName, records, userId, userDataKey);
}

View File

@@ -5,7 +5,8 @@ import type { SQLiteTable } from "drizzle-orm/sqlite-core";
type TableName = "users" | "ssh_data" | "ssh_credentials";
class SimpleDBOps {
static async insert<T extends Record<string, any>>(
static async insert<T extends Record<string, unknown>>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
table: SQLiteTable<any>,
tableName: TableName,
data: T,
@@ -44,8 +45,8 @@ class SimpleDBOps {
return decryptedResult as T;
}
static async select<T extends Record<string, any>>(
query: any,
static async select<T extends Record<string, unknown>>(
query: unknown,
tableName: TableName,
userId: string,
): Promise<T[]> {
@@ -58,16 +59,16 @@ class SimpleDBOps {
const decryptedResults = DataCrypto.decryptRecords(
tableName,
results,
results as unknown[],
userId,
userDataKey,
);
return decryptedResults;
return decryptedResults as T[];
}
static async selectOne<T extends Record<string, any>>(
query: any,
static async selectOne<T extends Record<string, unknown>>(
query: unknown,
tableName: TableName,
userId: string,
): Promise<T | undefined> {
@@ -81,7 +82,7 @@ class SimpleDBOps {
const decryptedResult = DataCrypto.decryptRecord(
tableName,
result,
result as Record<string, unknown>,
userId,
userDataKey,
);
@@ -89,10 +90,11 @@ class SimpleDBOps {
return decryptedResult;
}
static async update<T extends Record<string, any>>(
static async update<T extends Record<string, unknown>>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
table: SQLiteTable<any>,
tableName: TableName,
where: any,
where: unknown,
data: Partial<T>,
userId: string,
): Promise<T[]> {
@@ -108,7 +110,8 @@ class SimpleDBOps {
const result = await getDb()
.update(table)
.set(encryptedData)
.where(where)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.where(where as any)
.returning();
DatabaseSaveTrigger.triggerSave(`update_${tableName}`);
@@ -124,12 +127,17 @@ class SimpleDBOps {
}
static async delete(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
table: SQLiteTable<any>,
tableName: TableName,
where: any,
where: unknown,
_userId: string,
): Promise<any[]> {
const result = await getDb().delete(table).where(where).returning();
): Promise<unknown[]> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await getDb()
.delete(table)
.where(where as any)
.returning();
DatabaseSaveTrigger.triggerSave(`delete_${tableName}`);
@@ -145,12 +153,12 @@ class SimpleDBOps {
}
static async selectEncrypted(
query: any,
query: unknown,
_tableName: TableName,
): Promise<any[]> {
): Promise<unknown[]> {
const results = await query;
return results;
return results as unknown[];
}
}

View File

@@ -18,14 +18,14 @@ interface UserExportData {
userId: string;
username: string;
userData: {
sshHosts: any[];
sshCredentials: any[];
sshHosts: unknown[];
sshCredentials: unknown[];
fileManagerData: {
recent: any[];
pinned: any[];
shortcuts: any[];
recent: unknown[];
pinned: unknown[];
shortcuts: unknown[];
};
dismissedAlerts: any[];
dismissedAlerts: unknown[];
};
metadata: {
totalRecords: number;
@@ -83,7 +83,7 @@ class UserDataExport {
)
: sshHosts;
let sshCredentialsData: any[] = [];
let sshCredentialsData: unknown[] = [];
if (includeCredentials) {
const credentials = await getDb()
.select()
@@ -185,7 +185,10 @@ class UserDataExport {
return JSON.stringify(exportData, null, pretty ? 2 : 0);
}
static validateExportData(data: any): { valid: boolean; errors: string[] } {
static validateExportData(data: unknown): {
valid: boolean;
errors: string[];
} {
const errors: string[] = [];
if (!data || typeof data !== "object") {
@@ -193,23 +196,26 @@ class UserDataExport {
return { valid: false, errors };
}
if (!data.version) {
const dataObj = data as Record<string, unknown>;
if (!dataObj.version) {
errors.push("Missing version field");
}
if (!data.userId) {
if (!dataObj.userId) {
errors.push("Missing userId field");
}
if (!data.userData || typeof data.userData !== "object") {
if (!dataObj.userData || typeof dataObj.userData !== "object") {
errors.push("Missing or invalid userData field");
}
if (!data.metadata || typeof data.metadata !== "object") {
if (!dataObj.metadata || typeof dataObj.metadata !== "object") {
errors.push("Missing or invalid metadata field");
}
if (data.userData) {
if (dataObj.userData) {
const userData = dataObj.userData as Record<string, unknown>;
const requiredFields = [
"sshHosts",
"sshCredentials",
@@ -218,23 +224,24 @@ class UserDataExport {
];
for (const field of requiredFields) {
if (
!Array.isArray(data.userData[field]) &&
!(
field === "fileManagerData" &&
typeof data.userData[field] === "object"
)
!Array.isArray(userData[field]) &&
!(field === "fileManagerData" && typeof userData[field] === "object")
) {
errors.push(`Missing or invalid userData.${field} field`);
}
}
if (
data.userData.fileManagerData &&
typeof data.userData.fileManagerData === "object"
userData.fileManagerData &&
typeof userData.fileManagerData === "object"
) {
const fileManagerData = userData.fileManagerData as Record<
string,
unknown
>;
const fmFields = ["recent", "pinned", "shortcuts"];
for (const field of fmFields) {
if (!Array.isArray(data.userData.fileManagerData[field])) {
if (!Array.isArray(fileManagerData[field])) {
errors.push(
`Missing or invalid userData.fileManagerData.${field} field`,
);