refactor(server): 清理全量 any 类型安全警告 (692 → 0)
- 全模块类型化:controller 的 req: any → AuthenticatedRequest/RequestUser, 聚合查询 getRawMany 泛型标注、导入行/响应体定义具体 interface、 catch (e: any) → unknown + 收窄、no-base-to-string 用 String() 显式转换 - 第三方无类型库边界(pdfkit/exceljs)文件级或单行 disable 并注明理由 - 顺带修复:get-business-context.tool 两个 require-await error、 bills.controller 参数顺序隐患、main.ts compression 调用 - 运行时逻辑零改动;测试 142 套件 / 1065 用例全部通过
This commit is contained in:
@@ -3,6 +3,16 @@ import { DataSource } from 'typeorm';
|
||||
import { uuidV7 } from '../common/uuid-v7';
|
||||
import { withQueryRunner } from './database-migrations.runner';
|
||||
|
||||
/** 迁移脚本中用到的 organizations 表最小行结构。 */
|
||||
interface OrganizationRow {
|
||||
id: number;
|
||||
}
|
||||
|
||||
/** String() 包装:避免 unknown 收窄后触发 no-base-to-string。 */
|
||||
function stringify(value: unknown): string {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
export async function backfillOrganizations(
|
||||
dataSource: DataSource,
|
||||
): Promise<void> {
|
||||
@@ -17,8 +27,8 @@ export async function backfillOrganizations(
|
||||
const tableNames = new Set(tables.map((table) => table.name));
|
||||
if (!tableNames.has('organizations')) return;
|
||||
|
||||
const organizationRows = () =>
|
||||
runner.query('SELECT * FROM organizations WHERE is_host = 1 LIMIT 1');
|
||||
const organizationRows = (): Promise<OrganizationRow[]> =>
|
||||
runner.query('SELECT * FROM organizations WHERE is_host = 1 LIMIT 1') as Promise<OrganizationRow[]>;
|
||||
let host = (await organizationRows())[0];
|
||||
if (!host) {
|
||||
await runner.query(
|
||||
@@ -39,14 +49,17 @@ export async function backfillOrganizations(
|
||||
if (!host) return;
|
||||
|
||||
if (tableNames.has('tenants')) {
|
||||
const legacyTenants: Array<Record<string, unknown>> =
|
||||
await runner.query('SELECT * FROM tenants');
|
||||
const legacyTenants = (await runner.query('SELECT * FROM tenants')) as Array<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
for (const legacy of legacyTenants) {
|
||||
const name = String(legacy.name || '').trim();
|
||||
const name = stringify(legacy.name || '').trim();
|
||||
if (!name) continue;
|
||||
let external = (
|
||||
await runner.query('SELECT * FROM organizations WHERE name = ? LIMIT 1', [name])
|
||||
)[0];
|
||||
const externalRows = (await runner.query(
|
||||
'SELECT * FROM organizations WHERE name = ? LIMIT 1',
|
||||
[name],
|
||||
)) as OrganizationRow[];
|
||||
let external = externalRows[0];
|
||||
if (!external) {
|
||||
await runner.query(
|
||||
`INSERT INTO organizations (public_id, code, name, is_host, contact_name, phone, color, notes, status, created_at, updated_at)
|
||||
@@ -64,7 +77,7 @@ export async function backfillOrganizations(
|
||||
],
|
||||
);
|
||||
external = (
|
||||
await runner.query('SELECT * FROM organizations WHERE name = ? LIMIT 1', [name])
|
||||
(await runner.query('SELECT * FROM organizations WHERE name = ? LIMIT 1', [name])) as OrganizationRow[]
|
||||
)[0];
|
||||
}
|
||||
if (!external) continue;
|
||||
@@ -158,7 +171,11 @@ export async function normalizeClassDates(
|
||||
.map((column) => `${column} = ${normalizedDate(column)}`)
|
||||
.join(',\n ');
|
||||
const predicates = columns.map((column) => needsNormalization(column)).join('\n OR ');
|
||||
const result = await dataSource.transaction((manager) =>
|
||||
interface UpdateResultLike {
|
||||
changes?: number;
|
||||
affectedRows?: number;
|
||||
}
|
||||
const result = await dataSource.transaction<UpdateResultLike | undefined>((manager) =>
|
||||
manager.query(`
|
||||
UPDATE classes
|
||||
SET
|
||||
|
||||
Reference in New Issue
Block a user