Typescript 방식의 몽구스…?
Typescript에서 Mongoose 모델을 구현하려고합니다. Google을 수색하는 것은 하이브리드 접근 방식 (JS와 TS 결합)만을 공개했습니다. JS없이 순진한 접근 방식으로 User 클래스를 구현하는 방법은 무엇입니까?
짐없이 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 {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
necroposting에 대해 죄송하지만 누군가에게는 여전히 흥미로울 수 있습니다. 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);
})();
시도해보십시오 ts-mongoose. 조건부 유형을 사용하여 매핑을 수행합니다.
import { createSchema, Type, typedModel } from 'ts-mongoose';
const UserSchema = createSchema({
username: Type.string(),
email: Type.string(),
});
const User = typedModel('User', UserSchema);
다른 방법을 추가하십시오.
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
}
설치 한 경우 @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 */
}));
추신 : 복사 된 @Hongbo Miao답변
다음은 몽구스 스키마와 일반 모델을 일치시키는 강력한 유형의 방법입니다. 컴파일러는 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);
이 vscode intellisense둘 모두에서 작동합니다.
- User Type User.findOne
- user instance u1._id
The Code:
// imports
import { ObjectID } from 'mongodb'
import { Document, model, Schema, SchemaDefinition } from 'mongoose'
import { authSchema, IAuthSchema } from './userAuth'
// the model
export interface IUser {
_id: ObjectID, // !WARNING: No default value in Schema
auth: IAuthSchema
}
// IUser will act like it is a Schema, it is more common to use this
// For example you can use this type at passport.serialize
export type IUserSchema = IUser & SchemaDefinition
// IUser will act like it is a Document
export type IUserDocument = IUser & Document
export const userSchema = new Schema<IUserSchema>({
auth: {
required: true,
type: authSchema,
}
})
export default model<IUserDocument>('user', userSchema)
Here is the example from Mongoose documentation, Creating from ES6 Classes Using loadClass(), converted to TypeScript:
import { Document, Schema, Model, model } from 'mongoose';
import * as assert from 'assert';
const schema = new Schema<IPerson>({ firstName: String, lastName: String });
export interface IPerson extends Document {
firstName: string;
lastName: string;
fullName: string;
}
class PersonClass extends Model {
firstName!: string;
lastName!: string;
// `fullName` becomes a virtual
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
set fullName(v) {
const firstSpace = v.indexOf(' ');
this.firstName = v.split(' ')[0];
this.lastName = firstSpace === -1 ? '' : v.substr(firstSpace + 1);
}
// `getFullName()` becomes a document method
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
// `findByFullName()` becomes a static
static findByFullName(name: string) {
const firstSpace = name.indexOf(' ');
const firstName = name.split(' ')[0];
const lastName = firstSpace === -1 ? '' : name.substr(firstSpace + 1);
return this.findOne({ firstName, lastName });
}
}
schema.loadClass(PersonClass);
const Person = model<IPerson>('Person', schema);
(async () => {
let doc = await Person.create({ firstName: 'Jon', lastName: 'Snow' });
assert.equal(doc.fullName, 'Jon Snow');
doc.fullName = 'Jon Stark';
assert.equal(doc.firstName, 'Jon');
assert.equal(doc.lastName, 'Stark');
doc = (<any>Person).findByFullName('Jon Snow');
assert.equal(doc.fullName, 'Jon Snow');
})();
For the static findByFullName method, I couldn't figure how get the type information Person, so I had to cast <any>Person when I want to call it. If you know how to fix that please add a comment.
ReferenceURL : https://stackoverflow.com/questions/34482136/mongoose-the-typescript-way
'programing' 카테고리의 다른 글
| COALESCE를 사용하여 PostgreSQL에서 NULL 값 처리 (0) | 2021.01.17 |
|---|---|
| 두 개의 탄소 타임 스탬프를 비교하는 방법은 무엇입니까? (0) | 2021.01.17 |
| app : srcCompat =“@ drawable / pic”의 ImageButton 속성을 프로그래밍 방식으로 설정하는 방법은 무엇입니까? (0) | 2021.01.17 |
| Electron 앱에서 메뉴 바 제거 (0) | 2021.01.17 |
| Xcode 9 : pid에 연결할 수 없습니다. (0) | 2021.01.17 |