- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在将我的 Express API 模板转换为 TypeScript,但我在存储库方面遇到了一些问题。
使用 JavaScript,我会做这样的事情:
export default class BaseRepository {
async all() {
return this.model.findAll();
}
// other common methods
}
import BaseRepository from './BaseRepository';
import { User } from '../Models';
export default class UserRepository extends BaseRepository {
constructor() {
super();
this.model = User;
}
async findByEmail(email) {
return this.model.findOne({
where: {
email,
},
});
}
// other methods
现在,对于 TypeScript,问题是它不知道 this.model
的类型,我无法将具体模型传递给 BaseRepository
,因为它是一个抽象。我发现 sequelize-typescript
导出一个 ModelCtor
,它声明所有静态模型方法,如 findAll、create 等,我还可以使用另一个 sequelize-typescript
导出,即 Model
来正确注释返回类型。
所以,我最终这样做了:
import { Model, ModelCtor } from 'sequelize-typescript';
export default abstract class BaseRepository {
protected model: ModelCtor;
constructor(model: ModelCtor) {
this.model = model;
}
public async all(): Promise<Model[]> {
return this.model.findAll();
}
// other common methods
}
import { Model } from 'sequelize-typescript';
import BaseRepository from './BaseRepository';
import { User } from '../Models';
export default class UserRepository extends BaseRepository {
constructor() {
super(User);
}
public async findByEmail(email: string): Promise<Model | null> {
return this.model.findOne({
where: {
email,
},
});
}
// other methods
}
好的,这行得通,TypeScript 不会提示诸如 findOne
或 create
之类的方法不存在,但这会产生另一个问题。
现在,例如,每当我从存储库中获得 User
时,如果我尝试访问其属性之一,如 user.email
,TypeScript 将提示该属性不存在。当然,因为类型Model
并不知道每个型号的具体情况。
好吧,那是
叛国罪
泛型。
现在 BaseRepository
使用方法也使用的通用 Model
类型:
export default abstract class BaseRepository<Model> {
public async all(): Promise<Model[]> {
return Model.findAll();
}
// other common methods
}
具体类将适当的模型传递给泛型:
import BaseRepository from './BaseRepository';
import { User } from '../Models';
export default class UserRepository extends BaseRepository<User> {
public async findByEmail(email: string): Promise<User | null> {
return User.findOne({
where: {
email,
},
});
}
// other methods
}
现在 IntelliSense 正确亮起,它显示抽象类和具体类方法以及模型属性(例如 user.email
)。
但是,如您所想,这会导致更多问题。
在 BaseRepository
中,方法使用 Model
泛型类型,TypeScript 提示 'Model' only refers to a type, but is being used as a value here
。不仅如此,TypeScript 也(再次)不知道模型中的静态方法存在,例如 findAll
、 create
等。
另一个问题是,在抽象类和具体类中,由于方法不再使用 this
,ESLint 期望方法是静态的:Expected 'this' to be used by class async method 'all'
。好的,我可以在整个文件中忽略这条规则,错误就消失了。将所有方法设置为静态会更好,这样我就不必实例化存储库,但也许我做梦太多了。
值得一提的是,虽然我可以用 // @ts-ignore
消除这些错误,但是当我执行它时,它不起作用:TypeError: Cannot read property 'create' of undefined\n at UserRepository.<anonymous>
我研究了很多,试图让所有的方法都是静态的,但是静态方法不能引用泛型类型(因为它被认为是一个实例属性),尝试了一些变通方法,试图在 BaseRepository
的构造函数中传递具体模型以及使用通用类型的类,但到目前为止似乎没有任何效果。
如果您想检查代码:https://github.com/andresilva-cc/express-api-template/tree/main/src/App/Repositories
编辑:
找到这个:Sequelize-Typescript typeof model
好的,我从那篇文章中删除了一些不必要的代码,这有点管用:
import { Model } from 'sequelize-typescript';
export default abstract class BaseRepository<M extends Model> {
constructor(protected model: typeof Model) {}
public async all(attributes?: string[]): Promise<M[]> {
// Type 'Model<{}, {}>[]' is not assignable to type 'M[]'.
// Type 'Model<{}, {}>' is not assignable to type 'M'.
// 'Model<{}, {}>' is assignable to the constraint of type 'M', but 'M' could be instantiated with a different subtype of constraint 'Model<any, any>'.
return this.model.findAll({
attributes,
});
}
import BaseRepository from './BaseRepository';
import { User } from '../Models';
export default class UserRepository extends BaseRepository<User> {
constructor() {
super(User);
}
}
我的意思是,如果我输入一些 // @ts-ignore
,它至少会执行,而且 IntelliSense 会完美亮起,但 TypeScript 会提示。
最佳答案
我们遇到了同样的问题。解决方案是使用抽象存储库类实现的接口(interface)声明返回类型。
接口(interface)代码:
export type RepoResult<M> = Promise<Result<M | undefined, RepoError | undefined>>;
export interface IRepo<M> {
save(model: M): RepoResult<M>;
findById(id: string): RepoResult<M>;
search(parameterName: string, parameterValue: string, sortBy: string, order: number, pageSize: number, pageNumber: number): RepoResult<M[]>;
getAll(): RepoResult<M[]>;
deleteById(id: string): RepoResult<M>;
findByIds(ids: string[]): RepoResult<M[]>;
deleteByIds(ids: string[]): RepoResult<any>;
};
抽象类代码:
export abstract class Repo<M extends sequelize.Model> implements IRepo<M> {
protected Model!: sequelize.ModelCtor<M>;
constructor(Model: sequelize.ModelCtor<M>) {
this.Model = Model;
}
public async save(doc: M) {
try {
const savedDoc = await doc.save();
return Result.ok(savedDoc);
} catch (ex: any) {
logger.error(ex);
return Result.fail(new RepoError(ex.message, 500));
}
}
public async findById(id: string) {
try {
const doc = await this.Model.findOne({where: {
id: id
}});
if (!doc) {
return Result.fail(new RepoError('Not found', 404));
}
return Result.ok(doc);
} catch (ex: any) {
return Result.fail(new RepoError(ex.message, 500));
}
}
}
希望对您有所帮助。祝你有美好的一天:)
编辑:结果是一个如下所示的类:
export class Result<V, E> {
public isSuccess: boolean;
public isFailure: boolean;
private error: E;
private value: V;
private constructor(isSuccess: boolean, value: V, error: E) {
if (isSuccess && error) {
throw new Error('Successful result must not contain an error');
} else if (!isSuccess && value) {
throw new Error('Unsuccessful error must not contain a value');
}
this.isSuccess = isSuccess;
this.isFailure = !isSuccess;
this.value = value;
this.error = error;
}
public static ok<V>(value: V): Result<V, undefined> {
return new Result(true, value, undefined);
}
public static fail<E>(error: E): Result<undefined, E> {
return new Result(false, undefined, error);
}
public getError(): E {
if (this.isSuccess) {
throw new Error('Successful result does not contain an error');
}
return this.error;
}
public getValue(): V {
if (this.isFailure) {
throw new Error('Unsuccessful result does not contain a value');
}
return this.value;
}
}
RepoError 类:
type RepoErrorCode = 404 | 500;
export class RepoError extends Error {
public code: RepoErrorCode;
constructor(message: string, code: RepoErrorCode) {
super(message);
this.code = code;
}
}
repo 结果类型:
export type RepoResult<M> = Promise<Result<M | undefined, RepoError | undefined>>;
您可以在下面的链接中找到有关该模式的更多信息: https://khalilstemmler.com/articles/enterprise-typescript-nodejs/functional-error-handling/
关于node.js - TypeScript - 带有 Sequelize 的存储库模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69051499/
我正在关注 Sequelize 纪录片。在 Model Definition 部分的底部,我想知道 sequelize 变量用于什么?我可以删除它吗? { sequelize, modelNa
我有这个原始 SQL 查询。 SELECT restaurants.name AS restaurant, ROUND((6371 * ACOS(COS(RADIANS(6.9271)
我有一个 postgres 数据库,我正在使用 Sequelize。从表 车辆 和 预订 我试图在给定开始日期和结束日期的情况下获得所有可用车辆。 如果我使用给定日期搜索 Bookings: Book
我正在尝试使用 HapiJS 和 Sequelize 开始一个项目,并且开始时,希望在没有 Sequelize CLI 的情况下使事情正常工作,以了解一切是如何结合在一起的。 我见过多个示例项目,例如
sequelize init:models 命令会创建一个“models”文件夹并添加一个 index.js。 有人能解释一下这个 index.js 文件到底做了什么,以及它如何适应 Sequeliz
查看此 Sequelize tutorial 中的 models/blog.js 定义. module.exports = (sequelize, type) => { return sequ
我收到一个错误 No overload matches this call 每当我尝试使用 @HasMany() 或 @BelongsTo 装饰器时。 我正在使用 nestjs/sequelize:
const gamem = await gamemodes.findAll({attributes: ['name']}); const newme = await gamemodes.fin
我们如何使用 sequelize 4.2 创建由所有模型应用/继承的自定义实例方法?在 Sequelize 3 中,我们曾经在扩展到所有其他模型的主模型的“定义”部分中有一个“instanceMeth
我正在使用 Typescript、NodeJS 和sequelize-auto-ts 进行模型生成。我想要放置包含查找查询的两个模型给了我错误的结果,这又是由于触发了错误的查询。这是有问题的两个模型;
假设我在用户表中有 5 列 name email state isOnline createdAt | N
我有两张表,其中一张表具有另一张表的 ID。 1:1 关系。 所以像 EventFeedback somePrimaryKey userEventID UserEvent us
如何使用对象创建具有现有关联的条目? 例如, User.create({ socialMedia: [{ socialId: 1, //should reference existing
如何创建在创建 Sequelize 模型的新实例时以编程方式生成的默认值?我已经在某处阅读了如何执行此操作,但在任何地方都找不到。我以为这与classMethods有关,但我不知道应该调用什么方法。
当我设置关联时,有没有办法使用 Sequelize (sequelizejs.com) 输出所有在对象上神奇创建的函数。 例如;我有一个用户模型,我设置 User.belongsToMany(User
我该如何制作 Music是`音乐? { id: 4 name: "playlist 1" created_at: "2015-04-21T21:43:07.000Z" updated_
我可以使用 sequelize 从可用模型创建数据库模式吗?我在一个缺少许多迁移且没有测试的项目上工作。要运行测试,我需要创建一个新的 db (sqlite3),但我无法使用迁移初始化其架构(因为它们
我有一个与其他模型相关联的简单 Sequelize 模型。 module.exports = function (sequelize, DataTypes) { var Votes = seque
我有一个像这样设置的协会: m.User.hasMany(m.Interests, { joinTableName: 'user_interests', foreignKey: 'user_id' }
我有以下型号: var User = Seq.define('user', { firstName: { type: Sequelize.STRING,
我是一名优秀的程序员,十分优秀!