明确告诉打字稿一个变量不为空

Explicitly tell typescript that a variable is not null

我遇到打字稿问题。我有一个猫鼬模型,上面有一个接口。

import { Schema, model } from "mongoose";

interface IUser {
    userId: string
    guildId: string
    cash: number
    bank: number
}

const userSchema = new Schema<IUser>({
    userId: { type: String, required: true },
    guildId: { type: String, required: true },
    cash: { type: Number, required: true },
    bank: { type: Number, required: true }
});

const User = model<IUser>("User", userSchema);

export default User;

现在,每当我导入它时,都会从集合中找到一个文档并尝试访问 属性 之类的 userDocument.cash 打字稿会引发错误:Object is possibly 'null' 如下面的代码片段所示:

import UserModel from "path/to/model";
// some code (not relevant)
if (!(UserModel.findOne({ userId: user.id, guildId: i.guildId }))) newUser(i.guild!, user); // It checks if an user document exists and if not it creates one. (user.id and i.guildId are defined)
const userDocument = await UserModel.findOne({ userId: user.id, guildId: i.guildId });
console.log(userDocument.cash) // typescript error: Object is possibly 'null'
//          ~~~~~~~~~~~~

在这里,我们显然知道该文档存在,我们可以使用 ! 运算符告诉它打字稿(所以它将是:console.log(userDocument!.cash))。问题是这不能很好地扩展,每次我想使用 userDocument 时我都必须添加 !。所以我的问题是:有没有办法明确地告诉打字稿变量不为空?

到目前为止,我已经找到了两个解决方法,但其中 none 令人满意。

  1. 我们可以将 IUser 接口转换为 userDocument 变量,但随后我们将无法访问所有其他与文档相关的 properties/methods,例如 document.save。 我发现将变量转换为 IUser 接口来解决这个问题,但这不是一个完美的解决方案,因为我丢失了所有其他与文档相关的属性,例如 document.save():
const userDocument = await UserModel.findOne({ userId: user.id, guildId: i.guildId }) as IUser;
userDocument.cash = 300;
userDocument.save() // typescript error: Property 'save' does not exist on type 'IUser'.
//           ~~~~
  1. 另一个工作得很好,但对我来说太难看了:
let userDocument = await UserModel.findOne({ userId: user.id, guildId: i.guildId });
userDocument = userDocument!
userDocument.cash = 300;
userDocument.save() // works

我已阅读 post 但我看不出任何方法可以将其解决方案转化为我的问题。

您可以将 ! 添加到等待表达式本身。这样您就不必像尝试#2 那样重新分配变量。

const userDocument = (await UserModel.findOne({ userId: user.id, guildId: i.guildId }))!;

请注意,由于运算符优先级规则,await 需要用括号括起来,并且 ! 后缀运算符必须在括号外。