feat(core): 启用 TypeScript 最严格的类型检查 (#199)

* feat(core):  启用 TypeScript 最严格的类型检查

* ci: 配置 Codecov 以适应类型安全改进

* fix(core): 修复 CodeQL 安全警告

* fix(core): eslint.config.mjs
This commit is contained in:
YHH
2025-10-31 16:14:23 +08:00
committed by GitHub
parent 011d795361
commit c58e3411fd
56 changed files with 622 additions and 495 deletions

View File

@@ -8,11 +8,24 @@ import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
import {
getSerializationMetadata,
isSerializable,
SerializationMetadata
getSerializationMetadata
} from './SerializationDecorators';
/**
* 可序列化的值类型
*/
export type SerializableValue =
| string
| number
| boolean
| null
| undefined
| SerializableValue[]
| { [key: string]: SerializableValue }
| { __type: 'Date'; value: string }
| { __type: 'Map'; value: Array<[SerializableValue, SerializableValue]> }
| { __type: 'Set'; value: SerializableValue[] };
/**
* 序列化后的组件数据
*/
@@ -30,7 +43,7 @@ export interface SerializedComponent {
/**
* 组件数据
*/
data: Record<string, any>;
data: Record<string, SerializableValue>;
}
/**
@@ -53,12 +66,12 @@ export class ComponentSerializer {
const componentType = component.constructor as ComponentType;
const typeName = metadata.options.typeId || getComponentTypeName(componentType);
const data: Record<string, any> = {};
const data: Record<string, SerializableValue> = {};
// 序列化标记的字段
for (const [fieldName, options] of metadata.fields) {
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
const value = (component as any)[fieldName];
const value = (component as unknown as Record<string | symbol, SerializableValue>)[fieldName];
// 跳过忽略的字段
if (metadata.ignoredFields.has(fieldName)) {
@@ -125,7 +138,7 @@ export class ComponentSerializer {
? options.deserializer(serializedValue)
: this.deserializeValue(serializedValue);
(component as any)[fieldName] = value;
(component as unknown as Record<string | symbol, SerializableValue>)[fieldName] = value;
}
return component;
@@ -178,7 +191,7 @@ export class ComponentSerializer {
*
* 处理基本类型、数组、对象等的序列化
*/
private static serializeValue(value: any): any {
private static serializeValue(value: SerializableValue): SerializableValue {
if (value === null || value === undefined) {
return value;
}
@@ -219,11 +232,12 @@ export class ComponentSerializer {
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.serializeValue(value[key]);
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
const result: Record<string, SerializableValue> = {};
const obj = value as Record<string, SerializableValue>;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = this.serializeValue(obj[key]);
}
}
return result;
@@ -236,7 +250,7 @@ export class ComponentSerializer {
/**
* 默认值反序列化
*/
private static deserializeValue(value: any): any {
private static deserializeValue(value: SerializableValue): SerializableValue {
if (value === null || value === undefined) {
return value;
}
@@ -248,14 +262,15 @@ export class ComponentSerializer {
}
// 处理特殊类型标记
if (type === 'object' && value.__type) {
switch (value.__type) {
if (type === 'object' && typeof value === 'object' && '__type' in value) {
const typedValue = value as { __type: string; value: SerializableValue };
switch (typedValue.__type) {
case 'Date':
return new Date(value.value);
return { __type: 'Date', value: typeof typedValue.value === 'string' ? typedValue.value : String(typedValue.value) };
case 'Map':
return new Map(value.value);
return { __type: 'Map', value: typedValue.value as Array<[SerializableValue, SerializableValue]> };
case 'Set':
return new Set(value.value);
return { __type: 'Set', value: typedValue.value as SerializableValue[] };
}
}
@@ -265,11 +280,12 @@ export class ComponentSerializer {
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.deserializeValue(value[key]);
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
const result: Record<string, SerializableValue> = {};
const obj = value as Record<string, SerializableValue>;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = this.deserializeValue(obj[key]);
}
}
return result;

View File

@@ -5,7 +5,6 @@
*/
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
import { IScene } from '../IScene';

View File

@@ -7,7 +7,6 @@
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
import { SerializedEntity } from './EntitySerializer';
import { ComponentType } from '../Core/ComponentStorage';
@@ -204,7 +203,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
parentId: entity.parent?.id
...(entity.parent && { parentId: entity.parent.id })
});
// 快照组件
@@ -286,7 +285,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
parentId: entity.parent?.id,
...(entity.parent && { parentId: entity.parent.id }),
components: [],
children: []
}
@@ -325,7 +324,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
parentId: entity.parent?.id
...(entity.parent && { parentId: entity.parent.id })
}
});
}

View File

@@ -6,7 +6,6 @@
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
import { getComponentTypeName } from '../Decorators';
@@ -514,7 +513,7 @@ export class SceneSerializer {
return {
valid: errors.length === 0,
version: data.version,
errors: errors.length > 0 ? errors : undefined
...(errors.length > 0 && { errors })
};
} catch (error) {
return {
@@ -543,7 +542,7 @@ export class SceneSerializer {
return {
name: data.name,
version: data.version,
timestamp: data.timestamp,
...(data.timestamp !== undefined && { timestamp: data.timestamp }),
entityCount: data.metadata?.entityCount || data.entities.length,
componentTypeCount: data.componentTypeRegistry.length
};

View File

@@ -63,7 +63,7 @@ export class VersionMigrationManager {
public static registerComponentMigration(
componentType: string,
fromVersion: number,
toVersion: number,
_toVersion: number,
migration: ComponentMigrationFunction
): void {
if (!this.componentMigrations.has(componentType)) {
@@ -98,7 +98,7 @@ export class VersionMigrationManager {
*/
public static registerSceneMigration(
fromVersion: number,
toVersion: number,
_toVersion: number,
migration: SceneMigrationFunction
): void {
this.sceneMigrations.set(fromVersion, migration);