Pick 类型上不存在属性“_id”

Posted

技术标签:

【中文标题】Pick 类型上不存在属性“_id”【英文标题】:Property '_id' does not exist on type Pick 【发布时间】:2021-01-11 20:39:15 【问题描述】:

我正在使用 Next.js,我正在尝试使用 TypeScript 和 mongoose 查询 MongoDB,但我遇到了类型错误。

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&lt;&gt;[] 我做错了什么?

package.json

  "dependencies": 
    "mongoose": "^5.10.6",
...
  ,
  "devDependencies": 
    "@types/mongoose": "^5.7.36",
...
  

dbConnect() 是我从 Next.js 示例中获取的函数

【问题讨论】:

【参考方案1】:

这是因为您告诉编译器 data 可能是一个数组,在这种情况下需要对单个对象进行不同的访问。

findOne 不返回数组,findOne 只返回 Record&lt;string, T&gt;null。您应该从类型联合中删除 Pick&lt;dbPost, '_id' | 'post' | 'user'&gt;[]

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 && 
    ...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&lt;&gt; 中的字段匹配。

【讨论】:

正确,但是当我使用您的解决方案时,编译器仍然抱怨类型联合:Type 'Pick&lt;any, string | number | symbol&gt; | Pick&lt;any, string | number | symbol&gt;[]' is not assignable to type 'Pick&lt;dbPost, "_id" | "post" | "user"&gt;' Type 'Pick&lt;any, string | number | symbol&gt;[]' is missing the following properties from type 'Pick&lt;dbPost, "_id" | "post" | "user"&gt;': _id, post, userts(2322) @Diego,也许那是因为您还需要添加 .exec() 才能实际执行查询:await Post.findOne( 'post.slug': slug ).lean().select('-__v').exec() 我试过了。它没有改变错误。我现在将此函数移至 .js 文件。我不太了解,但是猫鼬的类型声明可能存在问题。我稍后会回到这个。谢谢。

以上是关于Pick 类型上不存在属性“_id”的主要内容,如果未能解决你的问题,请参考以下文章

“文档”类型上不存在猫鼬属性“x”

类型“typeof ...”上不存在属性“use”,类型“typeof”上不存在属性“extend”

TypeScript:类型“”上不存在属性

错误 TS2339:类型“”上不存在属性“包含”

类型“”上不存在属性“forEach”

类型“”上不存在 Typescript 错误属性“成员”