Reputation: 73
I'm using Next.js and I'm trying to query MongoDB with TypeScript and mongoose, but I have a type error.
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
}
I'm getting the following error:
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)
What is it about Pick<>[]
that I am doing wrong?
package.json
"dependencies": {
"mongoose": "^5.10.6",
...
},
"devDependencies": {
"@types/mongoose": "^5.7.36",
...
}
dbConnect() is a function I took from the Next.js examples
Upvotes: 1
Views: 1969
Reputation: 2579
This is because you've told the compiler that data
could be an array and in that case requires different accesses to singular objects.
findOne
does not return an array, findOne
only returns a Record<string, T>
or null
. You should remove the Pick<dbPost, '_id' | 'post' | 'user'>[]
from your type union.
const data:
| Pick<dbPost, '_id' | 'post' | 'user'>
| null = await Post.findOne({ 'post.slug': slug }).lean().select('-__v')
Now data
could still be null
so you need to just make sure you aren't accessing properties on null
. The whole function:
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 && {
...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
}
To ensure type-correctness also make sure your select
matches the fields in your Pick<>
.
Upvotes: 1