![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
ts-mongoose
Advanced tools
Automatically infer TypeScript interfaces from mongoose schemas.
npm i ts-mongoose mongoose @types/mongoose
yarn add ts-mongoose mongoose @types/mongoose
When using mongoose and Typescript, you must define schemas and interfaces. Both definitions must be maintained separately and must match each other. It can be error-prone during development and cause overhead.
ts-mongoose
is a very lightweight library that allows you to create a mongoose schema and a typescript type from a common definition.
All types as created from 1-liner functions and does not depend on decorators❗️.
For example:
Type.string()
returns {type: String, required: true}
, which is the same definition required in the original mongoose library.
Before:
import { Schema, model, Model, Document } from 'mongoose';
const AddressSchema = new Schema({
city: { type: String, required: true },
country: String,
zip: String,
}, { _id: false, timestamps: true });
const PhoneSchema = new Schema({
phoneNumber: { type: Schema.Types.Number, required: true },
name: String
})
const UserSchema = new Schema({
title: { type: String, required: true },
author: { type: String, required: true },
body: { type: String, required: true },
comments: [
{
body: { type: String, required: true },
date: { type: Date, required: true },
},
],
date: { type: Date, default: Date.now, required: true },
hidden: { type: Boolean, required: true },
meta: {
votes: { type: Schema.Types.Number },
favs: { type: Schema.Types.Number },
},
m: {
type: Schema.Types.Mixed,
required: true,
},
gender: {
type: Schema.Types.String,
required: true,
enum: ['male', 'female']
},
otherId: {
type: Schema.Types.ObjectId,
required: true,
},
address: {
type: AddressSchema,
required: true,
},
phones: {
type: [PhoneSchema],
required: true,
},
}, { timestamps: { createdAt: true } });
interface UserProps extends Document {
title: string;
author: string;
body: string;
// Duplicate all props from the above schema :(
}
const User: Model<UserProps> = model('User', UserSchema);
🎉🎉🎉 After:
import { createSchema, Type, typedModel } from 'ts-mongoose';
const genders = ['male', 'female'] as const;
const AddressSchema = createSchema({
city: Type.string(),
country: Type.optionalString(),
zip: Type.optionalString(),
}, { _id: false, timestamps: true });
const PhoneSchema = createSchema({
phoneNumber: Type.number(),
name: Type.optionalString(),
});
const UserSchema = createSchema({
title: Type.string(),
author: Type.string(),
body: Type.string(),
comments: Type.array().of({
body: Type.string(),
date: Type.date(),
}),
date: Type.date({ default: Date.now as any }),
hidden: Type.boolean(),
meta: Type.object().of({
votes: Type.number(),
favs: Type.number(),
}),
m: Type.mixed(),
gender: Type.string({ enum: genders }),
otherId: Type.objectId(),
address: Type.schema().of(AddressSchema),
phones: Type.array().of(PhoneSchema),
}, { timestamps: { createdAt: true } });
const User = typedModel('User', UserSchema);
User.findById('123').then(user => {
if (user) {
user. // autocomplete here
}
});
{
// same as {type: String}
firstName: Type.optionalString(),
// same as {type: String, required: true}
email: Type.string(),
}
{
// same as {type: String, required: true, unique: true, index: true}
email: Type.string({unique: true, index: true})
}
const genders = ['male', 'female'] as const;
{
// same as {type: String, required: true, enum: ['male', 'female']}
gender: Type.string({enum: genders})
}
schema
, object
, array
types have a method of
where you must provide a child type{
// same as {type: [String], required: true}
tags: Type.array().of(Type.string())
}
schema.of(ExampleSchema)
has typical for Subdocument additional fields and methods. Setting { _id: false }
in SchemaOptions won't attach _id
property in Subdocumentconst AddressSchema = createSchema({city: Type.string()}, { _id: false, timestamps: true });
{
// same as {type: AddressSchema}
address: Type.schema().of(AddressSchema)
}
// address property has city property, other Subdocument methods and properties except '_id'
array.of(ExampleSchema)
will return DocumentArray instead of standard arrayconst PhoneSchema = createSchema({phoneNumber: Type.number()}, { _id: false });
{
// same as {type: [PhoneSchema]}
phones: Type.schema().of(PhoneSchema)
}
// phones property has such methods as create(), id(), but also those typical for arrays like map(), filter() etc
ref
is a special type for creating references{
// same as [{type: Schema.Types.ObjectId, ref: 'Comment'}]
comments: Type.array().of(
Type.ref(Type.objectId()).to('Comment', CommentSchema)
),
}
populateTs(property: string)
use this function to populate a property and adjust the returned type automatically. Under the hood it calls only the native populate
method.// models.ts
import 'ts-mongoose/plugin'
User.find().populateTs('comments');
Use ExtractDoc
to extract generated document type.
Use ExtractProps
to extract generated base model properties.
Example:
import { createSchema, Type, typedModel, ExtractDoc, ExtractProps } from 'ts-mongoose';
export const UserSchema = createSchema({
email: Type.string(),
username: Type.string(),
isBlocked: Type.optionalBoolean(),
});
export const User = typedModel('User', UserSchema);
export type UserDoc = ExtractDoc<typeof UserSchema>;
export type UserProps = ExtractProps<typeof UserSchema>;
// example function
async function blockUser(user: UserDoc) {
user.isBlocked = true;
// access all properties + Document methods and properties
await user.save();
}
function randomUser(): UserProps {
// must return `email`, `username`
// `isBlocked` is optional
return {
email: 'user1@example.com',
username: 'user1',
}
}
Refs and populations are supported.
Check code under example/example4.ts
.
If you need to specify custom fields in the model, you can add a fake annotation.
It's only required if you add virtual fields or custom methods to the model.
const UserSchema = createSchema({
title: Type.string(),
author: Type.string(),
...({} as {
generatedField: string;
customFunction: () => number;
}),
});
const User = typedModel('User', UserSchema);
Autocomplete popup:
MIT
FAQs
Automatically infer TypeScript interfaces from mongoose schemas.
The npm package ts-mongoose receives a total of 1,559 weekly downloads. As such, ts-mongoose popularity was classified as popular.
We found that ts-mongoose demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.