为什么Generics不扩展DeepPartial



我正在使用这个GitHub存储库中的NestJS的干净架构https://github.com/hvpaiva/clean-architecture-nestjs.

更新包后,我发现BaseRepository有问题,尤其是这个和类似的部分(save、softRemove(

save<T extends DeepPartial<Entity>>(
entityOrEntities: T | T[],
options?: SaveOptions,
): Promise<T | T[]> {
return this.manager.save<T>(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}

错误显示

TS2322: Type 'Promise<DeepPartial<Entity>[]>' is not assignable to type 'Promise<T | T[]>'.
Type 'DeepPartial<Entity>[]' is not assignable to type 'T | T[]'.
Type 'DeepPartial<Entity>[]' is not assignable to type 'T[]'.
Type 'DeepPartial<Entity>' is not assignable to type 'T'.
'DeepPartial<Entity>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ObjectLiteral | { [x: string]: any; }'.
Type 'Entity' is not assignable to type 'T'.
'Entity' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ObjectLiteral | { [x: string]: any; }'.

包装为:

"dependencies": {
"@godaddy/terminus": "^4.11.2",
"@nestjs/common": "^9.1.6",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.1.6",
"@nestjs/platform-express": "^9.1.6",
"@nestjs/swagger": "^6.1.3",
"@nestjs/terminus": "^9.1.2",
"@nestjs/typeorm": "^9.0.1",
"body-parser": "^1.20.1",
"cache-manager": "^5.1.1",
"chalk": "^5.1.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"compression": "^1.7.4",
"cross-env": "^7.0.3",
"express-rate-limit": "^6.6.0",
"helmet": "^6.0.0",
"pg": "^8.8.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.7",
"swagger-ui-express": "^4.5.0",
"typeorm": "^0.3.10"
},
"devDependencies": {
"@nestjs/cli": "^9.1.5",
"@nestjs/schematics": "^9.0.3",
"@nestjs/testing": "^9.1.6",
"@types/compression": "^1.7.2",
"@types/express": "^4.17.14",
"@types/express-rate-limit": "^5.1.3",
"@types/helmet": "^0.0.48",
"@types/jest": "29.2.0",
"@types/lodash": "^4.14.186",
"@types/node": "^18.11.8",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.41.0",
"@typescript-eslint/parser": "^5.41.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-import-helpers": "^1.3.1",
"jest": "^29.2.2",
"lodash": "^4.17.21",
"prettier": "^2.7.1",
"start-server-webpack-plugin": "^2.2.5",
"supertest": "^6.3.1",
"ts-jest": "29.0.3",
"ts-loader": "^9.4.1",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.0",
"typescript": "^4.8.4",
"webpack-node-externals": "^3.0.0"
}

完整的BaseRepository.ts文件

import {
ObjectLiteral,
EntityManager,
QueryRunner,
DeepPartial,
SaveOptions,
RemoveOptions,
InsertResult,
ObjectID,
FindConditions,
UpdateResult,
DeleteResult,
FindManyOptions,
FindOneOptions,
EntitySchema,
Connection,
} from 'typeorm';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
export class BaseRepository<Entity extends ObjectLiteral> {
readonly manager: EntityManager;
readonly queryRunner?: QueryRunner;
readonly entitySchema: EntitySchema<Entity>;
constructor(connection: Connection, entity: EntitySchema<Entity>) {
this.queryRunner = connection.createQueryRunner();
this.manager = this.queryRunner.manager;
this.entitySchema = entity;
}
hasId(entity: Entity): boolean {
return this.manager.hasId(entity);
}
getId(entity: Entity): any {
return this.manager.getId(entity);
}
create(): Entity;
create(entityLikeArray: DeepPartial<Entity>[]): Entity[];
create(entityLike: DeepPartial<Entity>): Entity;
create(
plainEntityLikeOrPlainEntityLikes?:
| DeepPartial<Entity>
| DeepPartial<Entity>[],
): Entity | Entity[] {
return this.manager.create<any>(
this.entitySchema as any,
plainEntityLikeOrPlainEntityLikes as any,
);
}
merge(
mergeIntoEntity: Entity,
...entityLikes: DeepPartial<Entity>[]
): Entity {
return this.manager.merge(
this.entitySchema as any,
mergeIntoEntity,
...entityLikes,
);
}
preload(entityLike: DeepPartial<Entity>): Promise<Entity | undefined> {
return this.manager.preload(this.entitySchema as any, entityLike);
}
save<T extends DeepPartial<Entity>>(
entities: T[],
options: SaveOptions & { reload: false },
): Promise<T[]>;
save<T extends DeepPartial<Entity>>(
entities: T[],
options?: SaveOptions,
): Promise<(T & Entity)[]>;
save<T extends DeepPartial<Entity>>(
entity: T,
options: SaveOptions & { reload: false },
): Promise<T>;
save<T extends DeepPartial<Entity>>(
entity: T,
options?: SaveOptions,
): Promise<T & Entity>;
save<T extends DeepPartial<Entity>>(
entityOrEntities: T | T[],
options?: SaveOptions,
): Promise<T | T[]> {
return this.manager.save<T>(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}
remove(entities: Entity[], options?: RemoveOptions): Promise<Entity[]>;
remove(entity: Entity, options?: RemoveOptions): Promise<Entity>;
remove(
entityOrEntities: Entity | Entity[],
options?: RemoveOptions,
): Promise<Entity | Entity[]> {
return this.manager.remove(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}
softRemove<T extends DeepPartial<Entity>>(
entities: T[],
options: SaveOptions & { reload: false },
): Promise<T[]>;
softRemove<T extends DeepPartial<Entity>>(
entities: T[],
options?: SaveOptions,
): Promise<(T & Entity)[]>;
softRemove<T extends DeepPartial<Entity>>(
entity: T,
options: SaveOptions & { reload: false },
): Promise<T>;
softRemove<T extends DeepPartial<Entity>>(
entity: T,
options?: SaveOptions,
): Promise<T & Entity>;
softRemove<T extends DeepPartial<Entity>>(
entityOrEntities: T | T[],
options?: SaveOptions,
): Promise<T | T[]> {
return this.manager.softRemove<T>(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}
recover<T extends DeepPartial<Entity>>(
entities: T[],
options: SaveOptions & { reload: false },
): Promise<T[]>;
recover<T extends DeepPartial<Entity>>(
entities: T[],
options?: SaveOptions,
): Promise<(T & Entity)[]>;
recover<T extends DeepPartial<Entity>>(
entity: T,
options: SaveOptions & { reload: false },
): Promise<T>;
recover<T extends DeepPartial<Entity>>(
entity: T,
options?: SaveOptions,
): Promise<T & Entity>;
recover<T extends DeepPartial<Entity>>(
entityOrEntities: T | T[],
options?: SaveOptions,
): Promise<T | T[]> {
return this.manager.recover<T>(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}
insert(
entity: QueryDeepPartialEntity<Entity> | QueryDeepPartialEntity<Entity>[],
): Promise<InsertResult> {
return this.manager.insert(this.entitySchema as any, entity);
}
update(
criteria:
| string
| string[]
| number
| number[]
| Date
| Date[]
| ObjectID
| ObjectID[]
| FindConditions<Entity>,
partialEntity: QueryDeepPartialEntity<Entity>,
): Promise<UpdateResult> {
return this.manager.update(
this.entitySchema as any,
criteria as any,
partialEntity,
);
}
delete(
criteria:
| string
| string[]
| number
| number[]
| Date
| Date[]
| ObjectID
| ObjectID[]
| FindConditions<Entity>,
): Promise<DeleteResult> {
return this.manager.delete(this.entitySchema as any, criteria as any);
}
softDelete(
criteria:
| string
| string[]
| number
| number[]
| Date
| Date[]
| ObjectID
| ObjectID[]
| FindConditions<Entity>,
): Promise<UpdateResult> {
return this.manager.softDelete(this.entitySchema as any, criteria as any);
}
restore(
criteria:
| string
| string[]
| number
| number[]
| Date
| Date[]
| ObjectID
| ObjectID[]
| FindConditions<Entity>,
): Promise<UpdateResult> {
return this.manager.restore(this.entitySchema as any, criteria as any);
}
count(options?: FindManyOptions<Entity>): Promise<number>;
count(conditions?: FindConditions<Entity>): Promise<number>;
count(
optionsOrConditions?: FindManyOptions<Entity> | FindConditions<Entity>,
): Promise<number> {
return this.manager.count(
this.entitySchema as any,
optionsOrConditions as any,
);
}
find(options?: FindManyOptions<Entity>): Promise<Entity[]>;
find(conditions?: FindConditions<Entity>): Promise<Entity[]>;
find(
optionsOrConditions?: FindManyOptions<Entity> | FindConditions<Entity>,
): Promise<Entity[]> {
return this.manager.find(
this.entitySchema as any,
optionsOrConditions as any,
);
}
findAndCount(options?: FindManyOptions<Entity>): Promise<[Entity[], number]>;
findAndCount(
conditions?: FindConditions<Entity>,
): Promise<[Entity[], number]>;
findAndCount(
optionsOrConditions?: FindManyOptions<Entity> | FindConditions<Entity>,
): Promise<[Entity[], number]> {
return this.manager.findAndCount(
this.entitySchema as any,
optionsOrConditions as any,
);
}
findByIds(ids: any[], options?: FindManyOptions<Entity>): Promise<Entity[]>;
findByIds(ids: any[], conditions?: FindConditions<Entity>): Promise<Entity[]>;
findByIds(
ids: any[],
optionsOrConditions?: FindManyOptions<Entity> | FindConditions<Entity>,
): Promise<Entity[]> {
return this.manager.findByIds(
this.entitySchema as any,
ids,
optionsOrConditions as any,
);
}
findOne(
id?: string | number | Date | ObjectID,
options?: FindOneOptions<Entity>,
): Promise<Entity | undefined>;
findOne(options?: FindOneOptions<Entity>): Promise<Entity | undefined>;
findOne(
conditions?: FindConditions<Entity>,
options?: FindOneOptions<Entity>,
): Promise<Entity | undefined>;
findOne(
optionsOrConditions?:
| string
| number
| Date
| ObjectID
| FindOneOptions<Entity>
| FindConditions<Entity>,
maybeOptions?: FindOneOptions<Entity>,
): Promise<Entity | undefined> {
return this.manager.findOne(
this.entitySchema as any,
optionsOrConditions as any,
maybeOptions,
);
}
findOneOrFail(
id?: string | number | Date | ObjectID,
options?: FindOneOptions<Entity>,
): Promise<Entity>;
findOneOrFail(options?: FindOneOptions<Entity>): Promise<Entity>;
findOneOrFail(
conditions?: FindConditions<Entity>,
options?: FindOneOptions<Entity>,
): Promise<Entity>;
findOneOrFail(
optionsOrConditions?:
| string
| number
| Date
| ObjectID
| FindOneOptions<Entity>
| FindConditions<Entity>,
maybeOptions?: FindOneOptions<Entity>,
): Promise<Entity> {
return this.manager.findOneOrFail(
this.entitySchema as any,
optionsOrConditions as any,
maybeOptions,
);
}
query(query: string, parameters?: any[]): Promise<any> {
return this.manager.query(query, parameters);
}
clear(): Promise<void> {
return this.manager.clear(this.entitySchema);
}
increment(
conditions: FindConditions<Entity>,
propertyPath: string,
value: number | string,
): Promise<UpdateResult> {
return this.manager.increment(
this.entitySchema,
conditions,
propertyPath,
value,
);
}
decrement(
conditions: FindConditions<Entity>,
propertyPath: string,
value: number | string,
): Promise<UpdateResult> {
return this.manager.decrement(
this.entitySchema,
conditions,
propertyPath,
value,
);
}
async transaction<T>(operation: () => Promise<T>): Promise<T> {
await this.queryRunner.connect();
await this.queryRunner.startTransaction();
try {
const result = await operation();
await this.queryRunner.commitTransaction();
return result;
} catch (err) {
await this.queryRunner.rollbackTransaction();
} finally {
await this.queryRunner.release();
}
}
}

我发现这个讨论没有帮助:https://github.com/typeorm/typeorm/issues/8681

我做了一项研究,试图在DeepPartial中进行更改,但无济于事。我的期望是解决导致错误的问题。

实际的问题是因为save方法也需要Entity。


save<T extends DeepPartial<Entity>>(
entityOrEntities: T | T[],
options?: SaveOptions,
): Promise<T | T[]> {
return this.manager.save<Entity, T>(
this.entitySchema as any,
entityOrEntities as any,
options,
);
}

最新更新