#mongodb #typescript #mongoose #next.js
#mongodb #typescript #мангуст #next.js
Вопрос:
Я использую Next.js и я пытаюсь запросить MongoDB с помощью TypeScript и mongoose, но у меня ошибка типа.
types.d.ts
type dbPost = {
_id: string
user: {
uid: string
name: string
avatar: string
}
post: {
title: string
description: string
markdown: string
slug: string
createdAt: string
}
}
export const getSlugData = async (slug: string) => {
await dbConnect()
const data:
| Pick<dbPost, '_id' | 'post' | 'user'>
// The problem seems to be here with Pick[]
| Pick<dbPost, '_id' | 'post' | 'user'>[]
| null = await Post.findOne({ 'post.slug': slug }).lean().select('-__v')
const post = {
...data,
_id: `${data._id}`,
// _id and createdAt are objects created by mongoose which can't be serialized.
// They must be converted to a string
post: {
...data.post,
createdAt: `${data.post.createdAt}`,
},
}
return post
}
Я получаю следующую ошибку:
Property '_id' does not exist on type 'Pick<dbPost, "_id" | "post" | "user"> | Pick<dbPost, "_id" | "post" | "user">[]'.
Property '_id' does not exist on type 'Pick<dbPost, "_id" | "post" | "user">[]'.ts(2339)
Pick<>[]
Что я делаю не так?
package.json
"dependencies": {
"mongoose": "^5.10.6",
...
},
"devDependencies": {
"@types/mongoose": "^5.7.36",
...
}
DBConnect() — это функция, которую я взял из Next.js примеры
Ответ №1:
Это потому, что вы сообщили компилятору, что data
это может быть массив, и в этом случае требуются разные обращения к отдельным объектам.
findOne
не возвращает массив, findOne
только возвращает Record<string, T>
или null
. Вы должны удалить Pick<dbPost, '_id' | 'post' | 'user'>[]
из вашего объединения типов.
const data:
| Pick<dbPost, '_id' | 'post' | 'user'>
| null = await Post.findOne({ 'post.slug': slug }).lean().select('-__v')
Теперь data
все еще может быть null
так, что вам нужно просто убедиться, что вы не обращаетесь к свойствам null
. Вся функция:
export const getSlugData = async (slug: string) => {
await dbConnect()
const data:
| Pick<dbPost, '_id' | 'post' | 'user'>
| null = await Post.findOne({ 'post.slug': slug }).lean().select('-__v')
// first check if data is null
const post = data amp;amp; {
...data,
_id: `${data._id}`,
// _id and createdAt are objects created by mongoose which can't be serialized.
// They must be converted to a string
post: {
...data.post,
createdAt: `${data.post.createdAt}`,
},
}
return post
}
Для обеспечения корректности типа также убедитесь, что ваш select
соответствует полям в вашем Pick<>
.
Комментарии:
1. Правильно, но когда я использую ваше решение, компилятор по-прежнему жалуется на объединение типов:
Type 'Pick<any, string | number | symbol> | Pick<any, string | number | symbol>[]' is not assignable to type 'Pick<dbPost, "_id" | "post" | "user">' Type 'Pick<any, string | number | symbol>[]' is missing the following properties from type 'Pick<dbPost, "_id" | "post" | "user">': _id, post, userts(2322)
2. @Diego, возможно, это потому, что вам также нужно добавить
.exec()
, чтобы фактически выполнить запрос:await Post.findOne({ 'post.slug': slug }).lean().select('-__v').exec()
3. Я пробовал это. Это не изменило ошибку. На данный момент я переместил эту функцию в файл .js. Я мало что знаю, но может возникнуть проблема с объявлением типа мангустом. Я вернусь к этому позже. Спасибо.