明确告诉打字稿一个变量不为空
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 令人满意。
- 我们可以将 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'.
// ~~~~
- 另一个工作得很好,但对我来说太难看了:
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
需要用括号括起来,并且 !
后缀运算符必须在括号外。
我遇到打字稿问题。我有一个猫鼬模型,上面有一个接口。
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 令人满意。
- 我们可以将 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'.
// ~~~~
- 另一个工作得很好,但对我来说太难看了:
let userDocument = await UserModel.findOne({ userId: user.id, guildId: i.guildId });
userDocument = userDocument!
userDocument.cash = 300;
userDocument.save() // works
我已阅读
您可以将 !
添加到等待表达式本身。这样您就不必像尝试#2 那样重新分配变量。
const userDocument = (await UserModel.findOne({ userId: user.id, guildId: i.guildId }))!;
请注意,由于运算符优先级规则,await
需要用括号括起来,并且 !
后缀运算符必须在括号外。