Tim*_*ara 56 javascript mongoose node.js typescript
试图在Typescript中实现Mongoose模型.搜索谷歌只揭示了混合方法(结合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() {}
}
Run Code Online (Sandbox Code Playgroud)
Lou*_*kad 83
我是这样做的:
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;
Run Code Online (Sandbox Code Playgroud)
Gáb*_*mre 24
如果要分离类型定义和数据库实现,则另一种方法.
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 */
}));
Run Code Online (Sandbox Code Playgroud)
来自这里的灵感:https://github.com/Appsilon/styleguide/wiki/mongoose-typescript-models
Dan*_*scu 20
这里的大多数答案都重复了 TypeScript 类/接口和猫鼬模式中的字段。没有单一的真实来源意味着维护风险,因为项目变得更加复杂,并且有更多的开发人员在做它:字段更有可能不同步。当类与猫鼬模式位于不同的文件中时,这尤其糟糕。
为了保持字段同步,定义它们一次是有意义的。有几个库可以做到这一点:
我还没有完全相信他们中的任何一个,但 typegoose 似乎得到了积极维护,开发人员接受了我的 PR。
提前考虑一步:当您将 GraphQL 模式添加到组合中时,会出现另一层模型复制。克服这个问题的一种方法可能是从 GraphQL 模式生成 TypeScript 和mongoose代码。
Dim*_*oid 13
对不起,但这对某人来说仍然很有趣.我认为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);
})();
Run Code Online (Sandbox Code Playgroud)
对于现有的连接方案,您可以使用如下(在实际情况中可能更有可能并在文档中发现):
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);
})();
Run Code Online (Sandbox Code Playgroud)
小智 11
尝试ts-mongoose。它使用条件类型进行映射。
import { createSchema, Type, typedModel } from 'ts-mongoose';
const UserSchema = createSchema({
username: Type.string(),
email: Type.string(),
});
const User = typedModel('User', UserSchema);
Run Code Online (Sandbox Code Playgroud)
新推荐的输入文档的方式是使用单一界面。要在应用程序中输入文档,您应该使用HydratedDocument:
import { HydratedDocument, model, Schema } from "mongoose";
interface Animal {
name: string;
}
const animalSchema = new Schema<Animal>({
name: { type: String, required: true },
});
const AnimalModel = model<Animal>("Animal", animalSchema);
const animal: HydratedDocument<Animal> = AnimalModel.findOne( // ...
Run Code Online (Sandbox Code Playgroud)
Mongoose 建议不要扩展文档。
https://mongoosejs.com/docs/typescript.html
这是一种将普通模型与猫鼬模式相匹配的强类型方法。编译器将确保传递给 mongoose.Schema 的定义与接口匹配。一旦你有了架构,你就可以使用
常见的.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]>
};
Run Code Online (Sandbox Code Playgroud)
用户.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
);
Run Code Online (Sandbox Code Playgroud)
拥有架构后,您可以使用其他答案中提到的方法,例如
const userModel = mongoose.model<User & mongoose.Document>('User', schema);
Run Code Online (Sandbox Code Playgroud)
只需添加另一种方式:
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,
// ...
}));
Run Code Online (Sandbox Code Playgroud)
之间的差异interface,并type请阅读此答案
这种方式有一个优点,你可以添加Mongoose静态方法类型:
interface IUserModel extends IUser, mongoose.Document {
generateJwt: () => string
}
Run Code Online (Sandbox Code Playgroud)
如果您已经安装 @types/mongoose
npm install --save-dev @types/mongoose
Run Code Online (Sandbox Code Playgroud)
你可以这样
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 */
}));
Run Code Online (Sandbox Code Playgroud)
PS:复制@Hongbo Miao的答案
微软的人是这样做的。这里
import mongoose from "mongoose";
export type UserDocument = mongoose.Document & {
email: string;
password: string;
passwordResetToken: string;
passwordResetExpires: Date;
...
};
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
...
}, { timestamps: true });
export const User = mongoose.model<UserDocument>("User", userSchema);
Run Code Online (Sandbox Code Playgroud)
我建议您在将 TypeScript 添加到 Node 项目时查看这个出色的入门项目。
https://github.com/microsoft/TypeScript-Node-Starter
如果您想确保您的架构满足模型类型,反之亦然,此解决方案提供比 @bingles 建议更好的类型:
普通类型文件:(
ToSchema.ts别慌!复制粘贴即可)
import { Document, Schema, SchemaType, SchemaTypeOpts } from 'mongoose';
type NonOptionalKeys<T> = { [k in keyof T]-?: undefined extends T[k] ? never : k }[keyof T];
type OptionalKeys<T> = Exclude<keyof T, NonOptionalKeys<T>>;
type NoDocument<T> = Exclude<T, keyof Document>;
type ForceNotRequired = Omit<SchemaTypeOpts<any>, 'required'> & { required?: false };
type ForceRequired = Omit<SchemaTypeOpts<any>, 'required'> & { required: SchemaTypeOpts<any>['required'] };
export type ToSchema<T> = Record<NoDocument<NonOptionalKeys<T>>, ForceRequired | Schema | SchemaType> &
Record<NoDocument<OptionalKeys<T>>, ForceNotRequired | Schema | SchemaType>;
Run Code Online (Sandbox Code Playgroud)
和一个示例模型:
import { Document, model, Schema } from 'mongoose';
import { ToSchema } from './ToSchema';
export interface IUser extends Document {
name?: string;
surname?: string;
email: string;
birthDate?: Date;
lastLogin?: Date;
}
const userSchemaDefinition: ToSchema<IUser> = {
surname: String,
lastLogin: Date,
role: String, // Error, 'role' does not exist
name: { type: String, required: true, unique: true }, // Error, name is optional! remove 'required'
email: String, // Error, property 'required' is missing
// email: {type: String, required: true}, // correct
// Error, 'birthDate' is not defined
};
const userSchema = new Schema(userSchemaDefinition);
export const User = model<IUser>('User', userSchema);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
35329 次 |
| 最近记录: |