Reputation: 1017
import type { NextApiRequest, NextApiResponse } from "next";
import db from "../../app/libs/dbConn";
interface DataProps {
auth: [
{
name?: string;
email?: string;
passwordHash?: string;
}
];
status: number;
message: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<DataProps>
) {
if (req.method === "POST") {
const data = {
name: "Gary",
email: `gary@${Math.floor(Math.random() * 9999999)}.subdomain.com`,
passwordHash: "-",
};
const user = await db.user.create({ data });
return res
.status(200)
.json({ auth: [data], status: 201, message: "created user" });
}
if (req.method === "GET") {
const allUsers = await db.user.findMany();
const users = allUsers.map((user) => {
return {
name: user.name || "",
email: user.email || "",
passwordHash: "" || "",
};
});
return res
.status(200)
.json({ auth: users, status: 200, message: "success" });
}
return res.status(404).json({
auth: [{}],
status: 405,
message: "http verb not supported",
});
}
In the above "GET" section, Typescript reports "auth" as having an error. The error is -- Type '{ name: string; email: string; passwordHash: string; }[]' is not assignable to type '[{ name?: string | undefined; email?: string | undefined; passwordHash?: string | undefined; }]'. Target requires 1 element(s) but source may have fewer.ts(2322) user.ts(6, 3): The expected type comes from property 'auth' which is declared here on type 'DataProps'
I don't understand what I'm doing wrong here. Everything appears to be fine and if I ignore the Typescript error, it works as designed.
I'm missing something that I can't resolve.
Upvotes: 0
Views: 673
Reputation: 58342
You've declared auth
as [ { name?: string; email?: string; passwordHash?: string; }]
- in other words, it's a single-element tuple containing exactly one { name?: string; email?: string; passwordHash?: string; }
element. But the code is instead expecting { name?: string; email?: string; passwordHash?: string; }[]
- in other words, an array of any number of { name?: string; email?: string; passwordHash?: string; }
elements. So change DataProps.auth
to { name?: string; email?: string; passwordHash?: string; }[]
, and your code should work.
For more information, see the TypeScript Handbook's discussion of arrays and tuples.
More broadly, there are a few approaches you could take to declaring your types:
[{ name?: string; email?: string; passwordHash?: string; }]
) means that it always contains a single element. That's an odd choice (if I only had exactly one item, I'd just return it directly as { name?: string; email?: string; passwordHash?: string }
), but maybe your design has specific needs for it.{ name?: string; email?: string; passwordHash?: string }[]
) can have 0, 1, or unlimited items.({ name: string; email: string; passwordHash: string } | Record<string, never>)[]
). (For an explanation of Record<string, never>
, see here.)auth
property optional:
interface User {
name: string;
email: string;
passwordHash: string;
}
interface DataProps {
auth?: User[];
status: number;
message: string;
}
Or, probably better, use a union for the whole thing, to declare different types for success and error responses. Then TypeScript won't let me access properties without first checking that the response was successful. Taking advantage of TypeScript's type system like this can help make code easier to maintain.
interface DataProps {
auth: User[];
}
interface ErrorResponse {
status: number;
message: string;
error: true;
errorDetails?: ErrorDetails; // for example
}
type SuccessResponse<T> = T & {
status: number;
message: string;
error?: false;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<DataProps>
) {
Upvotes: 1