From 88c8c256e2cc2c8a6593cd5ae61075af6369946c Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Wed, 4 Mar 2026 14:03:23 +0800 Subject: [PATCH] fix: resolve TypeScript type errors across codebase - Add experimentalDecorators support in tsconfig.node.json for TypeORM entities - Fix mssql module import in order-resolver.ts (static vs dynamic import) - Extend ISqlType parameter types in sql-server.ts for NVarChar compatibility - Fix variable naming and type assertions in bip-users-dao.ts - Add proper type assertions for IPC call results in renderer hooks (useAuth, useCleaner, useExtractor, useValidation) - Add definite assignment assertions in config-manager.ts --- src/main/services/config/config-manager.ts | 6 ++- src/main/services/database/sql-server.ts | 8 +++- src/main/services/erp/order-resolver.ts | 37 ++++++++------- src/main/services/user/bip-users-dao.ts | 54 ++++++++++++---------- src/renderer/src/hooks/useAuth.ts | 33 +++++++++---- src/renderer/src/hooks/useCleaner.ts | 8 +++- src/renderer/src/hooks/useExtractor.ts | 8 +++- src/renderer/src/hooks/useValidation.ts | 21 +++++++-- tsconfig.node.json | 4 +- 9 files changed, 118 insertions(+), 61 deletions(-) diff --git a/src/main/services/config/config-manager.ts b/src/main/services/config/config-manager.ts index d27ba9d..71b8080 100644 --- a/src/main/services/config/config-manager.ts +++ b/src/main/services/config/config-manager.ts @@ -147,8 +147,8 @@ function validateEditableFields(settings: Partial): { */ export class ConfigManager { private static instance: ConfigManager | null = null - private envPath: string - private backupPath: string + private envPath!: string + private backupPath!: string private configCache: Map = new Map() private initialized: boolean = false @@ -214,6 +214,8 @@ export class ConfigManager { * @param key - Configuration key * @param defaultValue - Default value if key doesn't exist */ + public get(key: string): string | undefined + public get(key: string, defaultValue: string): string public get(key: string, defaultValue?: string): string | undefined { return this.configCache.get(key) ?? defaultValue } diff --git a/src/main/services/database/sql-server.ts b/src/main/services/database/sql-server.ts index 6482f81..848c292 100644 --- a/src/main/services/database/sql-server.ts +++ b/src/main/services/database/sql-server.ts @@ -114,7 +114,13 @@ export class SqlServerService implements IDatabaseService { */ async queryWithParams( sqlString: string, - params: Record + params: Record< + string, + { + value: unknown + type?: sql.ISqlType | sql.ISqlTypeFactoryWithLength | sql.ISqlTypeWithLength + } + > ): Promise { if (!this.pool) { throw new Error('Not connected to SQL Server. Call connect() first.') diff --git a/src/main/services/erp/order-resolver.ts b/src/main/services/erp/order-resolver.ts index 44198ea..120dcba 100644 --- a/src/main/services/erp/order-resolver.ts +++ b/src/main/services/erp/order-resolver.ts @@ -14,18 +14,10 @@ import type { IDatabaseService } from '../database' import { SqlServerService } from '../database/sql-server' import { createLogger } from '../logger' +import sql from 'mssql' const log = createLogger('OrderResolver') -// Dynamically import mssql for SQL Server parameter types -let mssql: typeof import('mssql') | null = null -async function getMssql() { - if (!mssql) { - mssql = await import('mssql') - } - return mssql -} - /** * Order mapping result */ @@ -251,18 +243,26 @@ export class OrderNumberResolver { const isSqlServer = this.dbService.type === 'sqlserver' const tableName = this.getTableName(DB_CONFIG.TABLE_NAME) - log.debug('Resolving production IDs', { count: productionIds.length, dbType: this.dbService.type }) + log.debug('Resolving production IDs', { + count: productionIds.length, + dbType: this.dbService.type + }) let result if (isSqlServer) { // Use queryWithParams for SQL Server with explicit parameter types - const sql = await getMssql() const placeholders = productionIds.map((_, idx) => `@p${idx}`).join(', ') - const params: Record = {} + const params: Record< + string, + { + value: string + type: sql.ISqlType | sql.ISqlTypeFactoryWithLength | sql.ISqlTypeWithLength + } + > = {} productionIds.forEach((id, idx) => { - params[`p${idx}`] = { value: id, type: sql.NVarChar } + params[`p${idx}`] = { value: id, type: sql.NVarChar(255) } }) const query = ` @@ -351,12 +351,17 @@ export class OrderNumberResolver { if (isSqlServer) { // Use queryWithParams for SQL Server with explicit parameter types - const sql = await getMssql() const placeholders = orderNumbers.map((_, idx) => `@p${idx}`).join(', ') - const params: Record = {} + const params: Record< + string, + { + value: string + type: sql.ISqlType | sql.ISqlTypeFactoryWithLength | sql.ISqlTypeWithLength + } + > = {} orderNumbers.forEach((id, idx) => { - params[`p${idx}`] = { value: id, type: sql.NVarChar } + params[`p${idx}`] = { value: id, type: sql.NVarChar(255) } }) const query = ` diff --git a/src/main/services/user/bip-users-dao.ts b/src/main/services/user/bip-users-dao.ts index 9008e0e..5355cba 100644 --- a/src/main/services/user/bip-users-dao.ts +++ b/src/main/services/user/bip-users-dao.ts @@ -121,8 +121,8 @@ export class BIPUsersDAO { ` const result = await (dbService as SqlServerService).queryWithParams(sqlString, { - username: { value: username, type: sql.NVarChar }, - password: { value: password, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) }, + password: { value: password, type: sql.NVarChar(255) } }) if (result.rows.length > 0) { @@ -177,7 +177,7 @@ export class BIPUsersDAO { ` const result = await (dbService as SqlServerService).queryWithParams(sqlString, { - computerName: { value: computerName, type: sql.NVarChar } + computerName: { value: computerName, type: sql.NVarChar(255) } }) if (result.rows.length > 0) { @@ -265,49 +265,55 @@ export class BIPUsersDAO { const tableName = this.getTableName() if (this.dbType === 'sqlserver') { - let sql: string - let params: Record + let sqlString: string + let params: Record< + string, + { + value: unknown + type?: sql.ISqlType | sql.ISqlTypeFactoryWithLength | sql.ISqlTypeWithLength + } + > if (computerName) { - sql = ` + sqlString = ` INSERT INTO ${tableName} (UserName, Password, UserType, ComputerNmae) VALUES (@username, @password, @userType, @computerName) ` params = { - username: { value: username, type: sql.NVarChar }, - password: { value: password, type: sql.NVarChar }, - userType: { value: userType, type: sql.NVarChar }, - computerName: { value: computerName, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) }, + password: { value: password, type: sql.NVarChar(255) }, + userType: { value: userType, type: sql.NVarChar(255) }, + computerName: { value: computerName, type: sql.NVarChar(255) } } } else { - sql = ` + sqlString = ` INSERT INTO ${tableName} (UserName, Password, UserType) VALUES (@username, @password, @userType) ` params = { - username: { value: username, type: sql.NVarChar }, - password: { value: password, type: sql.NVarChar }, - userType: { value: userType, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) }, + password: { value: password, type: sql.NVarChar(255) }, + userType: { value: userType, type: sql.NVarChar(255) } } } await (dbService as SqlServerService).queryWithParams(sqlString, params) return true } else { - let sql: string - let params: any[] + let sqlString: string + let params: unknown[] if (computerName) { - sql = ` + sqlString = ` INSERT INTO ${tableName} (UserName, Password, UserType, ComputerNmae) VALUES (?, ?, ?, ?) ` params = [username, password, userType, computerName] } else { - sql = ` + sqlString = ` INSERT INTO ${tableName} (UserName, Password, UserType) VALUES (?, ?, ?) @@ -343,8 +349,8 @@ export class BIPUsersDAO { ` await (dbService as SqlServerService).queryWithParams(sqlString, { - username: { value: username, type: sql.NVarChar }, - userType: { value: userType, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) }, + userType: { value: userType, type: sql.NVarChar(255) } }) return true } else { @@ -382,8 +388,8 @@ export class BIPUsersDAO { ` await (dbService as SqlServerService).queryWithParams(sqlString, { - username: { value: username, type: sql.NVarChar }, - newPassword: { value: newPassword, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) }, + newPassword: { value: newPassword, type: sql.NVarChar(255) } }) return true } else { @@ -419,7 +425,7 @@ export class BIPUsersDAO { ` await (dbService as SqlServerService).queryWithParams(sqlString, { - username: { value: username, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) } }) return true } else { @@ -455,7 +461,7 @@ export class BIPUsersDAO { ` const result = await (dbService as SqlServerService).queryWithParams(sqlString, { - username: { value: username, type: sql.NVarChar } + username: { value: username, type: sql.NVarChar(255) } }) return result.rows.length > 0 && (result.rows[0].count as number) > 0 } else { diff --git a/src/renderer/src/hooks/useAuth.ts b/src/renderer/src/hooks/useAuth.ts index 27d7fd1..4f77a5d 100644 --- a/src/renderer/src/hooks/useAuth.ts +++ b/src/renderer/src/hooks/useAuth.ts @@ -53,7 +53,11 @@ export function useAuth(): UseAuthReturn { setState((prev) => ({ ...prev, loading: true, error: null })) try { - const result = await window.electron.ipcRenderer.invoke('auth:login', credentials) + const result = (await window.electron.ipcRenderer.invoke('auth:login', credentials)) as { + success: boolean + userInfo?: UserInfo + error?: string + } if (result.success && result.userInfo) { setState({ @@ -85,7 +89,12 @@ export function useAuth(): UseAuthReturn { setState((prev) => ({ ...prev, loading: true, error: null })) try { - const result = await window.electron.ipcRenderer.invoke('auth:silentLogin') + const result = (await window.electron.ipcRenderer.invoke('auth:silentLogin')) as { + success: boolean + userInfo?: UserInfo + error?: string + requiresUserSelection?: boolean + } if (result.success && result.userInfo) { setState({ @@ -126,14 +135,18 @@ export function useAuth(): UseAuthReturn { const getCurrentUser = useCallback(async (): Promise => { try { - const result = await window.electron.ipcRenderer.invoke('auth:getCurrentUser') + const result = (await window.electron.ipcRenderer.invoke('auth:getCurrentUser')) as { + isAuthenticated: boolean + userInfo?: UserInfo + } if (result.isAuthenticated && result.userInfo) { + const userInfo = result.userInfo setState((prev) => ({ ...prev, - user: result.userInfo, + user: userInfo, isAuthenticated: true })) - return result.userInfo + return userInfo } return null } catch { @@ -143,7 +156,7 @@ export function useAuth(): UseAuthReturn { const getAllUsers = useCallback(async (): Promise => { try { - return await window.electron.ipcRenderer.invoke('auth:getAllUsers') + return (await window.electron.ipcRenderer.invoke('auth:getAllUsers')) as UserInfo[] } catch { return [] } @@ -153,7 +166,11 @@ export function useAuth(): UseAuthReturn { setState((prev) => ({ ...prev, loading: true, error: null })) try { - const result = await window.electron.ipcRenderer.invoke('auth:switchUser', userInfo) + const result = (await window.electron.ipcRenderer.invoke('auth:switchUser', userInfo)) as { + success: boolean + userInfo?: UserInfo + error?: string + } if (result.success && result.userInfo) { setState({ @@ -180,7 +197,7 @@ export function useAuth(): UseAuthReturn { const isAdmin = useCallback(async (): Promise => { try { - return await window.electron.ipcRenderer.invoke('auth:isAdmin') + return (await window.electron.ipcRenderer.invoke('auth:isAdmin')) as boolean } catch { return false } diff --git a/src/renderer/src/hooks/useCleaner.ts b/src/renderer/src/hooks/useCleaner.ts index 5e2f088..4c10960 100644 --- a/src/renderer/src/hooks/useCleaner.ts +++ b/src/renderer/src/hooks/useCleaner.ts @@ -44,9 +44,13 @@ export function useCleaner(): UseCleanerReturn { setState({ loading: true, data: null, error: null }) try { - const result = await window.electron.ipcRenderer.invoke('cleaner:run', input) + const result = (await window.electron.ipcRenderer.invoke('cleaner:run', input)) as { + success: boolean + data?: CleanerResult + error?: string + } - if (result.success) { + if (result.success && result.data) { setState({ loading: false, data: result.data, error: null }) return result.data } else { diff --git a/src/renderer/src/hooks/useExtractor.ts b/src/renderer/src/hooks/useExtractor.ts index f42e2ad..0bf54e0 100644 --- a/src/renderer/src/hooks/useExtractor.ts +++ b/src/renderer/src/hooks/useExtractor.ts @@ -43,9 +43,13 @@ export function useExtractor(): UseExtractorReturn { setState({ loading: true, data: null, error: null }) try { - const result = await window.electron.ipcRenderer.invoke('extractor:run', input) + const result = (await window.electron.ipcRenderer.invoke('extractor:run', input)) as { + success: boolean + data?: ExtractorResult + error?: string + } - if (result.success) { + if (result.success && result.data) { setState({ loading: false, data: result.data, error: null }) return result.data } else { diff --git a/src/renderer/src/hooks/useValidation.ts b/src/renderer/src/hooks/useValidation.ts index 262ad31..42f0ea2 100644 --- a/src/renderer/src/hooks/useValidation.ts +++ b/src/renderer/src/hooks/useValidation.ts @@ -68,13 +68,18 @@ export function useValidation(): UseValidationReturn { setState((prev) => ({ ...prev, loading: true, error: null })) try { - const result = await window.electron.ipcRenderer.invoke('validation:validate', request) + const result = (await window.electron.ipcRenderer.invoke( + 'validation:validate', + request + )) as ValidationResponse if (result.success) { + const results = result.results || null + const stats = result.stats || null setState({ loading: false, - data: result.results || null, - stats: result.stats || null, + data: results, + stats: stats, error: null }) return result @@ -105,7 +110,9 @@ export function useValidation(): UseValidationReturn { const getSharedProductionIds = useCallback(async (): Promise => { try { - const result = await window.electron.ipcRenderer.invoke('validation:getSharedProductionIds') + const result = (await window.electron.ipcRenderer.invoke( + 'validation:getSharedProductionIds' + )) as { productionIds?: string[] } return result?.productionIds || [] } catch { return [] @@ -117,7 +124,11 @@ export function useValidation(): UseValidationReturn { materialCodes: string[] } | null> => { try { - const result = await window.electron.ipcRenderer.invoke('validation:getCleanerData') + const result = (await window.electron.ipcRenderer.invoke('validation:getCleanerData')) as { + success: boolean + orderNumbers?: string[] + materialCodes?: string[] + } if (result.success) { return { orderNumbers: result.orderNumbers || [], diff --git a/tsconfig.node.json b/tsconfig.node.json index a2d0b14..37a47be 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -15,6 +15,8 @@ "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "esModuleInterop": true + "esModuleInterop": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true } }