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);
답변
여기에서 대부분의 답변은 TypeScript 클래스 / 인터페이스 및 몽구스 스키마의 필드를 반복합니다. 단일 소스 소스가 없다는 것은 프로젝트가 더 복잡해지고 더 많은 개발자가 작업하기 때문에 유지 관리 위험을 나타냅니다. 필드가 동기화되지 않을 가능성이 더 큽니다 . 이것은 클래스가 몽구스 스키마와 다른 파일에있을 때 특히 나쁩니다.
필드를 동기화 상태로 유지하려면 필드를 한 번 정의하는 것이 좋습니다. 이를 수행하는 몇 가지 라이브러리가 있습니다.
- typeodm.io- 전체 테스트 범위, 좋은 예, 아직 견인력 없음
- mongoose-decorators-ts- 최고의 영어, 아직 견인력 없음
- typegoose- 가장 인기있는 문서, 개선이 필요한 문서
- ts-mongoose- 두 번째로 많이 사용되는 데코레이터를 사용하지 않고 적극적으로 유지 관리하지 않습니다.
- 몽구스 스키마 데코레이터 -아직 견인력 없음
- mongoose-typescript- typegoose 포크
나는 아직 그들 중 누구에게도 완전히 확신하지 못했지만 typegoose는 적극적으로 유지되는 것처럼 보이며 개발자는 내 PR을 수락했습니다.
한발 앞서 생각하기 : GraphQL 스키마를 믹스에 추가하면 다른 계층의 모델 복제가 나타납니다. 이 문제를 극복하는 한 가지 방법 은 GraphQL 스키마에서 TypeScript 및 몽구스 코드 를 생성 하는 것입니다.
답변
다음은 몽구스 스키마와 일반 모델을 일치시키는 강력한 유형의 방법입니다. 컴파일러는 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);
답변
다른 방법을 추가하십시오 ( @types/mongoose
와 함께 설치해야 함 npm install --save-dev @types/mongoose
).
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
}