【发布时间】:2021-12-22 05:54:55
【问题描述】:
今天我遇到了一个我已经无法解决几个小时的错误,即使是在一个小型个人项目中也是如此。 我试图实现一个通用存储库的东西,一个非常基本的东西。 这里有几个类: 基础实体类:
import {EntityType, Fields} from "./decorators";
import {IEntity} from "./validation-interfaces";
import {applyProperties} from "./validation-core";
@EntityType()
export class Entity implements IEntity {
//used only by db impl
public _id:any;
@Fields.String(true)
key: string;
@Fields.String(true)
name: string;
@Fields.String()
organizationId?:string;
@Fields.String()
ownerKey?:string;
@Fields.DateTime(true)
createdAt: Date;
@Fields.String(true)
createdBy:string;
@Fields.DateTime(false, null)
lastUpdatedAt: Date;
@Fields.String(false, null)
lastUpdatedBy: string;
@Fields.Boolean(false, false)
recycled: boolean;
@Fields.DateTime(false, null)
lastRecycledAt?:Date;
@Fields.String(false, null)
lastRecycledBy?:string;
@Fields.DateTime(false, null)
lastRestoredAt?:Date;
@Fields.String(false, null)
lastRestoredBy?:string;
constructor(props:Partial<Entity>) {
this._id = props._id;
applyProperties(Entity, props, this);
}
}
一个组织类:
@EntityType()
export class Organization extends Entity {
@Fields.String(true)
companyName = "";
@Fields.String(true)
companyRegistrationCountryCode = "";
@Fields.String(true)
companyGovId = "";
@Fields.String()
websiteUrl = "";
@Fields.Boolean(false, false)
billingAddressInDifferentCountry = false;
@Fields.Boolean(false, false)
useDifferentEmailForInvoices = false;
@Fields.Boolean(false, false)
useDifferentContactPersonForInvoices = false;
@Fields.ObjectOf(AddressDetails, true, new AddressDetails({}))
billingAddress = new AddressDetails({});
constructor(props:Partial<Organization>) {
super(props);
applyProperties(Organization, props, this);
}
}
电子邮件消息类:
import {EntityType, Fields} from "../validation/decorators";
let {Entity, applyProperties} = require('../validation');
@EntityType()
export class EmailMessageParameters {
[name:string]:any;
constructor(values:any) {
Object.assign(this, values);
}
}
@EntityType("email-messages", 'eml')
export class EmailMessage extends Entity {
@Fields.String(true)
templateId: string;
@Fields.ObjectOf(EmailMessageParameters, true, new EmailMessageParameters({}))
parameters:any;
@Fields.String(true)
email:string;
@Fields.String(true)
displayName: string;
@Fields.String(true)
provider: string;
@Fields.String(false, null)
deliveryId: string;
@Fields.Boolean(false, false)
sent: boolean;
@Fields.Boolean(false, false)
failed:boolean;
@Fields.String(false, null)
errorMessage:string;
constructor(props:Partial<EmailMessage>) {
super(props);
applyProperties(EmailMessage, props, this);
}
}
以及回购工厂功能:
let reposMap = new Map<string, any>();
export type EntityConstructor<T extends Entity> = { new (props:Partial<T>):T};
export function getRepository<T extends Entity>(ctr: EntityConstructor<T>):Repository<T> {
let validator = getValidatorForConstructor(ctr, true);
let rep = reposMap.get(validator.id) as Repository<T>;
if (!rep) {
rep = new Repository<T>(ctr, validator.storageName, validator.idPrefix, validator.idStrength || 32);
reposMap.set(validator.id, rep);
}
return rep;
}
行之有效:
let organizations = getRepository(Organization);
还有让我发疯的台词:
let emailMessages = getRepository(EmailMessage);
因为一个荒谬的错误:
TS2345: Argument of type 'typeof EmailMessage' is not assignable to parameter of type 'EntityConstructor<Entity>'.
Types of construct signatures are incompatible.<br/>Type 'new (props: Partial<EmailMessage>) => EmailMessage' is not assignable to type 'new (props: Partial<Entity>) => Entity'.
Type 'EmailMessage' is missing the following properties from type 'Entity': _id, key, name, createdAt, and 4 more.
像这样的显式变体
let messagesRepository = getRepository<EmailMessage>(EmailMessage);
导致其他错误:
TS2344: Type 'EmailMessage' does not satisfy the constraint 'Entity'.
Type 'EmailMessage' is missing the following properties from type 'Entity': _id, key, name, createdAt, and 4 more.
还记得 EmailMessage 是 Entity 的子类吗?
通过清除缓存重新启动 Webstorm 没有帮助。
打字稿设置位于/src/tsconfig.json,仅影响src中的内容,浏览器的内容在其他文件夹static中进行webpack-ed,其中src存在自己的ts-loader。
/src/tsconfig.json的内容如下:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "Node",
"module": "commonjs",
"target": "ES2020",
"lib": ["ES2020"],
"sourceMap": true,
"outDir": "../build"
},
"include": ["./**/*.*"],
"exclude": [
"../node_modules"
],
"compileOnSave": true
}
上面提到的装饰器是纯粹的,它们不覆盖构造函数,不定义属性描述符等。只是一些元数据聚合用于一些代码,如存储库实现和表单生成。
感谢您抽出宝贵时间阅读我的长文。
【问题讨论】:
-
请提供最低限度的可重现示例,我的意思是,真的最低限度
-
我很着急,所以我只有一段真正的代码会出现问题。我将在几分钟内发布解决方法。
标签: typescript generics