【问题标题】:Make an exception at certain fields在某些领域例外
【发布时间】:2021-03-20 22:22:42
【问题描述】:

我有一个方法可以用.findOneAndUpdate 保存作者

AuthorInterface 看起来像这样:

    export interface AuthorInterface {
        name: string,
        bio: string,
        githubLink: string,
        stackoverflowLink: string,
        twitterLink: string,
        image: string,
        image_webp: string,
    }

在这种情况下,我需要在这里做一个例外。 imageimage_webp 是图像路径,因此我不能只覆盖这些值。我已经使用Omit 将其从AuthorInterface 参数中删除。

但是 typescript 仍然在 author: { ...author } 抱怨 image_webpimage 字段丢失。如何告诉 typescript 我不希望 imageimage_webp 属性出现在参数对象中?

    public saveAuthor(_id: mongoose.Types.ObjectId | string, author: Omit<AuthorInterface, "image" | "image_webp">): Promise<UserModelInterface | null> {
        return User.findOneAndUpdate({ _id }, { author: { ...author } }, { new: true }).exec()
    }

【问题讨论】:

    标签: javascript mongodb typescript mongoose


    【解决方案1】:

    像这样更改您的AuthorInterface

    export interface AuthorInterface {
        name: string,
        bio: string,
        githubLink: string,
        stackoverflowLink: string,
        twitterLink: string,
        image?: string,
        image_webp?: string,
    }
    

    【讨论】:

    • 我可以,但我实际上也在其他地方使用 AuthorInterface。所以我不想简单地将它设置为可选
    • @Ifaruki 因为您不想更改AuthorInterface,所以当您不想要这些属性时,为什么不直接将imageimage_webp 设置为' ' 而不是从中删除它们对象?
    【解决方案2】:

    这就是打字稿的美妙之处。

    public saveAuthor(_id: mongoose.Types.ObjectId | string, author: unknown): Promise<UserModelInterface | null> {
        return User.findOneAndUpdate({ _id }, { author: author as AuthorInterface }, { new: true }).exec()
    }
    

    【讨论】:

    • 禁用 typescript的美
    【解决方案3】:

    这是我的解决方案:

    import mongoose from 'mongoose'
    
    interface AuthorInterface {
            name: string,
            bio: string,
            githubLink: string,
            stackoverflowLink: string,
            twitterLink: string,
            image: string,
            image_webp: string,
    }
    
    type AuthorUpdate = Omit<AuthorInterface, "image" | "image_webp">;
    
    /**
     * I'd willing to bet, that you can change/update/modify
     * User object/class
     * 
     * Here what you should do:
     */
    interface User {
            findOneAndUpdate: <T>(arg1: any, author: AuthorUpdate extends T ? AuthorUpdate : T, arg3: any) => any
    }
    
    /**
     * User mock, just for test purpose
     */
    const User: User = {
            findOneAndUpdate: (...args: any[]) => { }
    }
    
    /**
     * Now, if you pass AuthorUpdate to findOneAndUpdate it should work as expected
     */
    function saveAuthor(_id: mongoose.Types.ObjectId | string, author: AuthorUpdate) {
            return User.findOneAndUpdate({ _id }, { author: { ...author } }, { new: true }).exec()
    }
    
    /**
     * If you have problems with my solution, please share the minimum reproducable example
     */
    

    【讨论】:

      【解决方案4】:

      对于您的saveAuthor 函数,该函数仅使用author 克隆并传递给User.findOneAndUpdate

      简单来说,你可以输入saveAuthor的参数为:

      author: Parameters<(typeof User)['findOneAndUpdate']>[1].author
      

      这是一种丑陋的说法:“这个函数期望 User.findOneAndUpdate 期望的东西”。

      但更好的方法是使用已建立的类型。假设 findOneAndUpdate 在 author 属性的第二个参数中接受 AuthorInterface,只需写:

      author: AuthorInterface
      

      但是您正在尝试删除属性.. 您的这种说法听起来很奇怪:

      imageimage_webp 是图像路径,因此我不能只覆盖这些值”。

      但是你没有修改saveAuthor 中的这些属性。您是否担心User.findOneAndUpdate 修改属性?这无关紧要,因为您正在使用扩展运算符克隆对象:{ ...author }

      听起来您可能将类型与值混淆了。使用Omit 不会从实际值中删除属性;它只是放宽参数的类型要求。在大多数情况下,您仍然可以使用 imageimage_webp 传入一个对象(除非您正在编写 literal 对象,否则 typescript 的“过度属性检查”启发式不会启动)。

      您似乎误解了author: { ...author } 的打字稿错误。你说“我如何告诉 typescript 我不希望这些属性出现在这个对象中?”但错误不是关于你的 saveAuthor 函数所期望的,而是关于 User.findOneAndUpdate 所期望的。你给它传递了一个缺陷 AuthorInterface(不是一个完整的AuthorInterface),但它需要一个完整 AuthorInterface

      如果User.findOneAndUpdate 要求太多,那么您可以更改它以放宽其参数类型。如果您尝试删除这些值,请执行以下操作:

      author: {
          ...author,
          image: undefined,
          image_webp: undefined,
      }
      

      如果User.findOneAndUpdate 的类型不接受这一点,则使用 nancy 的答案修复它们,假设代码支持此可选性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-14
        • 2012-04-07
        • 1970-01-01
        • 2010-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多