Попытка реализовать модель Mongoose в Typescript. Очистка Google выявила только гибридный подход (сочетающий JS и TS). Как можно было бы реализовать класс User, по моему довольно наивному подходу, без JS?
Хотите, чтобы IUserModel без багажа.
import {IUser} from './user.ts';
import {Document, Schema, Model} from 'mongoose';
// mixing in a couple of interfaces
interface IUserDocument extends IUser, Document {}
// mongoose, why oh why '[String]'
// TODO: investigate out why mongoose needs its own data types
let userSchema: Schema = new Schema({
userName : String,
password : String,
firstName : String,
lastName : String,
email : String,
activated : Boolean,
roles : [String]
});
// interface we want to code to?
export interface IUserModel extends Model<IUserDocument> {/* any custom methods here */}
// stumped here
export class User {
constructor() {}
}
Вот как я это делаю:
export interface IUser extends mongoose.Document {
name: string;
somethingElse?: number;
};
export const UserSchema = new mongoose.Schema({
name: {type:String, required: true},
somethingElse: Number,
});
const User = mongoose.model<IUser>('User', UserSchema);
export default User;
import * as mongoose from 'mongoose';
или import mongoose = require('mongoose');
Другая альтернатива, если вы хотите отделить свои определения типов и реализацию базы данных.
import {IUser} from './user.ts';
import * as mongoose from 'mongoose';
type UserType = IUser & mongoose.Document;
const User = mongoose.model<UserType>('User', new mongoose.Schema({
userName : String,
password : String,
/* etc */
}));
Вдохновение отсюда: https://github.com/Appsilon/styleguide/wiki/mongoose-typescript-models
Извините за некропост, но кому-то это может быть интересно. Я думаю, что Typegoose предоставляет более современный и элегантный способ определения моделей
Вот пример из документации:
import { prop, Typegoose, ModelType, InstanceType } from 'typegoose';
import * as mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/test');
class User extends Typegoose {
@prop()
name?: string;
}
const UserModel = new User().getModelForClass(User);
// UserModel is a regular Mongoose Model with correct types
(async () => {
const u = new UserModel({ name: 'JohnDoe' });
await u.save();
const user = await UserModel.findOne();
// prints { _id: 59218f686409d670a97e53e0, name: 'JohnDoe', __v: 0 }
console.log(user);
})();
Для существующего сценария подключения вы можете использовать следующее (что может быть более вероятным в реальных ситуациях и раскрыто в документации):
import { prop, Typegoose, ModelType, InstanceType } from 'typegoose';
import * as mongoose from 'mongoose';
const conn = mongoose.createConnection('mongodb://localhost:27017/test');
class User extends Typegoose {
@prop()
name?: string;
}
// Notice that the collection name will be 'users':
const UserModel = new User().getModelForClass(User, {existingConnection: conn});
// UserModel is a regular Mongoose Model with correct types
(async () => {
const u = new UserModel({ name: 'JohnDoe' });
await u.save();
const user = await UserModel.findOne();
// prints { _id: 59218f686409d670a97e53e0, name: 'JohnDoe', __v: 0 }
console.log(user);
})();
typegoose
не имеет достаточной поддержки ... проверяя их статистику npm, это всего лишь 3 тыс. Еженедельных загрузок, и, таким образом, существует почти 100 открытых проблем Github, большинство из которых не имеют комментариев и некоторые из которых выглядят так, как будто они должны были быть закрыты давным-давно
Просто добавьте другой способ:
import { IUser } from './user.ts';
import * as mongoose from 'mongoose';
interface IUserModel extends IUser, mongoose.Document {}
const User = mongoose.model<IUserModel>('User', new mongoose.Schema({
userName: String,
password: String,
// ...
}));
И разница между interface
и type
, пожалуйста, прочитайте этот ответ
Этот способ имеет преимущество, вы можете добавить типичные статические методы Mongoose:
interface IUserModel extends IUser, mongoose.Document {
generateJwt: () => string
}
generateJwt
?
const User = mongoose.model.... password: String, generateJwt: () => { return someJwt; } }));
по сути, generateJwt
становится еще одним свойством модели.
Если вы установили @types/mongoose
npm install --save-dev @types/mongoose
Вы можете так
import {IUser} from './user.ts';
import { Document, Schema, model} from 'mongoose';
type UserType = IUser & Document;
const User = model<UserType>('User', new Schema({
userName : String,
password : String,
/* etc */
}));
PS: Скопировано @Hongbo Miao
ответ
Попробуйте ts-mongoose
. Он использует условные типы для отображения.
import { createSchema, Type, typedModel } from 'ts-mongoose';
const UserSchema = createSchema({
username: Type.string(),
email: Type.string(),
});
const User = typedModel('User', UserSchema);
Здесь строгий типизированный способ сопоставления простой модели со схемой мангуста. Компилятор гарантирует, что определения, переданные в mongoose.Schema, соответствуют интерфейсу. Как только у вас есть схема, вы можете использовать
common.ts
export type IsRequired<T> =
undefined extends T
? false
: true;
export type FieldType<T> =
T extends number ? typeof Number :
T extends string ? typeof String :
Object;
export type Field<T> = {
type: FieldType<T>,
required: IsRequired<T>,
enum?: Array<T>
};
export type ModelDefinition<M> = {
[P in keyof M]-?:
M[P] extends Array<infer U> ? Array<Field<U>> :
Field<M[P]>
};
user.ts
import * as mongoose from 'mongoose';
import { ModelDefinition } from "./common";
interface User {
userName : string,
password : string,
firstName : string,
lastName : string,
email : string,
activated : boolean,
roles : Array<string>
}
// The typings above expect the more verbose type definitions,
// but this has the benefit of being able to match required
// and optional fields with the corresponding definition.
// TBD: There may be a way to support both types.
const definition: ModelDefinition<User> = {
userName : { type: String, required: true },
password : { type: String, required: true },
firstName : { type: String, required: true },
lastName : { type: String, required: true },
email : { type: String, required: true },
activated : { type: Boolean, required: true },
roles : [ { type: String, required: true } ]
};
const schema = new mongoose.Schema(
definition
);
Если у вас есть схема, вы можете использовать методы, упомянутые в других ответах, таких как
const userModel = mongoose.model<User & mongoose.Document>('User', schema);
User
не может быть классом, потому что его создание - асинхронная операция. Он должен вернуть обещание, поэтому вы должны вызватьUser.create({...}).then...
User
не может быть классом?