Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct typings without extending Document #11728

Closed
boojum opened this issue May 1, 2022 · 3 comments
Closed

Correct typings without extending Document #11728

boojum opened this issue May 1, 2022 · 3 comments
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary

Comments

@boojum
Copy link

boojum commented May 1, 2022

Do you want to request a feature or report a bug?
Neither a feature request nor a bug, rather a shy cry for help.

What is the current behavior?
I'm trying to use TypeScript to ensure type-safety for the defined models. To that end I'm following the documentation. And while I got most of it working as expected, few unresolved issues remain - and to those I can't find solutions in the official documentation.

Continuing with a user model from the documentation, extended to cover instance methods, query helpers, and virtuals. Take the following snippet:

import { connect, Schema, model } from 'mongoose'
import argon2 from 'argon2'
import { Model, Document, Query } from 'mongoose'

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

type User = {
  email: string
  firstName: string
  lastName: string
  password: string
}

type UserVirtuals = {
  fullName: string
}

type UserMethods = {
  verifyPassword: (plaintext: string) => Promise<boolean>
}

type UserQueryHelpers = {
  byEmail(email: string): Query<any, Document<User>> & UserQueryHelpers
}

type UserModel = Model<User, UserQueryHelpers, UserMethods, UserVirtuals>

type UserDocument = User & Document

const userSchema = new Schema<User, UserModel, UserMethods, UserQueryHelpers>(
  {
    email: { type: String, required: true, unique: true },
    firstName: { type: String, required: true },
    lastName: { type: String, required: true },
    password: { type: String, required: true },
  },
  {
    timestamps: true,
    toJSON: {
      versionKey: false,
      transform: function (_, ret: Optional<User, 'password'> & Document) {
        ret.id = ret._id
        delete ret._id
        delete ret.password
      },
    },
    toObject: {
      versionKey: false,
      transform: function (_, ret: Optional<User, 'password'> & Document) {
        ret.id = ret._id
        delete ret._id
        delete ret.password
      },
    },
  },
)

userSchema.pre<UserDocument>('save', async function (next) {
  if (this.isModified('password')) {
    const hashed = await argon2.hash(this.get('password'))
    this.set('password', hashed)
  }
  next()
})

userSchema.virtual<UserDocument>('fullName').get(function () {
  return `${this.firstName} ${this.lastName}`
})

userSchema.methods.verifyPassword = async function (
  plaintext: string,
): Promise<boolean> {
  return await argon2.verify(plaintext, this.password)
}

userSchema.query.byEmail = function (email: string) {
  return this.find({ email })
}

export const user = model<User, UserModel>('users', userSchema)

I'm left with seven TypeScript errors, and no idea how to approach them:

1
2
3
4
5
6
7

I was searching through the Github Issues but couldn't find any hints here. Searching through Gitter chat logs didn't help much either. I would appreciate any and all hints as to how I can make those pesky errors to go away.

If this was already approached and answered somewhere else, then my apologies!

Complimentary tsconfig.json:

{
  "ts-node": {
    "esm": true
  },
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": ["esnext"],

    "baseUrl": ".",
    "outDir": "dist",

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,

    "strict": true,

    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"]
}

Also, if relevant, eslintrc.cjs:

module.exports = {
  root: true,
  env: {
    es2022: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    'prettier',
  ],
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    tsconfigRootDir: __dirname,
    project: './tsconfig.json',
  },
  ignorePatterns: ['*.cjs', 'dist/*'],
  overrides: [
    {
      files: ['**/*.test.js'],
      env: { jest: true },
      plugins: ['jest'],
      extends: ['plugin:jest/recommended', 'plugin:jest/style'],
    },
  ],
  rules: {
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
  },
}

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

node -v
v18.0.0
npm view mongoose version
6.3.1
mongod --version
db version v5.0.7
@IslandRhythms IslandRhythms added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label May 2, 2022
@Uzlopak
Copy link
Collaborator

Uzlopak commented May 3, 2022

You could define this in typescript by providing this as first parameter with the correct typing.

function bla(this: User) {
this._id;
}

We are currently working on getting better typings. For this we the next step is to habe automatically typed models, by @mohammad0-0ahmad

I would say we should merge the open PR for the auto typings first and then touch the scope of those functions if necessary. @mohammad0-0ahmad this is not an invitation to also cover this in your PR :). Lets get your PR merged first...

@mohammad0-0ahmad
Copy link
Contributor

You could define this in typescript by providing this as first parameter with the correct typing.

function bla(this: User) { this._id; }

We are currently working on getting better typings. For this we the next step is to habe automatically typed models, by @mohammad0-0ahmad

I would say we should merge the open PR for the auto typings first and then touch the scope of those functions if necessary. @mohammad0-0ahmad this is not an invitation to also cover this in your PR :). Lets get your PR merged first...

Thanks for the mention @Uzlopak,
I've planned to cover virtuals and some other TS improvements, but in separate PR's to make them easier to get merged.

@boojum
Copy link
Author

boojum commented May 4, 2022

@Uzlopak @mohammad0-0ahmad
Just had a look at the PR - looks fantastic! I'll close this for now to not pollute the issue tracker. I'll revisit the issue when #11563 / #9715 will be ready.

Thanks for all your work on this project!

@boojum boojum closed this as completed May 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary
Projects
None yet
Development

No branches or pull requests

4 participants