I am trying to build a route with node and typescript where I can add products to a cart, however it is complaining about the interface.
Here is the interface in interfaces.ts:
import { Document } from "mongoose";
export interface IUser extends Document {
firstName: string;
lastName: string;
email: string;
password: string;
cart: ICart;
orders: IOrders[];
}
export interface ICart {
total: number;
count: number;
}
My model in UserModel.ts:
const UserSchema = new Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
validate: {
validator: function (str: string) {
return /^[\w-\.] @([\w-] \.) [\w-]{2,4}$/g.test(str);
},
message: (props: { value: string }) =>
`${props.value} is not a valid email`,
},
},
password: {
type: String,
required: true,
},
cart: {
type: Object,
default: {
total: 0,
count: 0,
},
},
orders: [{ type: mongoose.Schema.Types.ObjectId, ref: "Order" }],
});
const UserModel = mongoose.model<IUser>("User", UserSchema);
export default UserModel;
And lastly, the route in productRoutes.ts:
productRoutes.post('/add-to-cart', async(req, res)=> {
const {userId, productId, price} = req.body;
try {
const user = await UserModel.findById(userId);
const userCart = user.cart;
if(user.cart[productId]){
userCart[productId] = 1;
} else {
userCart[productId] = 1;
}
userCart.count = 1;
userCart.total = Number(userCart.total) Number(price);
if (user) {
user.cart = userCart;
user.markModified('cart');
await user.save();
}
res.status(200).json(user);
} catch (e) {
res.status(400).send(e);
}
})
The error I am getting is in productRoutes.ts, in my try catch, specifically in these two parts:
const userCart = user.cart; // Object is possibly 'null'
if(user.cart[productId]){ // Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ICart'.
userCart[productId] = 1; // Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ICart'.
} else {
userCart[productId] = 1; // Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ICart'.
}
What am I doing wrong, where do I type it and how do I index type "ICart"?
CodePudding user response:
Try this syntax:
const userCart = user.cart!;
CodePudding user response:
First error
const userCart = user.cart; // Object is possibly 'null'
TypeScript (rightfully) warns you that the user
object can be null (which would happen if the document is not found in the user collection).
Instead of muting the error with the non-null assertion operator !
, I suggest you make sure the document exists indeed:
const { userId, productId, price } = req.body;
const user = await UserModel.findById(userId);
if (!user) {
res.status(400).send("User not found");
return;
}
const userCart = user.cart; // no TS errors
Second error
if(user.cart[productId]){ // Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ICart'.
First, you want to properly type the request body, to let the compiler know the data type of productId
.
interface IAddToCartRequestBody {
userId: string;
productId: string;
price: number;
}
productRoutes.post('/add-to-cart', async (req: express.Request<any, any, IAddToCartRequestBody>, res) => {
const { userId, productId, price } = req.body;
...
Second, allow product IDs as keys
export interface ICart {
[productId: string]: number;
total: number;
count: number;
}
These updates combined should resolve all of the TypeScript errors (in strict mode).