Find APIs should possibly return undefined
camchenry opened this issue · comments
Hi, I am having multiple issues, the biggest of which currently is that the findMany
and findFirst
APIs do not allow for the possibility of returning undefined
, even though they may do so. This causes TypeScript to not be able to type check this properly and results in run-time type errors.
CodeSandbox example:
https://codesandbox.io/s/mswjs-undefined-type-error-omifi?file=/src/App.tsx
import { factory, primaryKey } from "@mswjs/data";
import {
EntityInstance,
PrimaryKeyDeclaration
} from "@mswjs/data/lib/glossary";
import * as faker from "faker";
const db = factory({
user: {
Id: primaryKey(faker.datatype.uuid),
firstName: () => "random data here"
}
});
// Seed the database
db.user.create({
Id: "ab4f631c-cca4-498f-a5aa-4828352a7c69",
firstName: "Test"
});
// Some time later, query the database:
// Get a user (e.g., GET /user/:userId call)
const user = db.user.findFirst({
where: {
Id: {
equals: "ab4f631c-cca4-498f-a5aa-4828352a7dawdawdc69"
}
}
});
// OK
console.log("This will NOT cause a run-time type error: ", user?.firstName);
// ERROR
console.log("This will cause a run-time type error: ", user.firstName);
I think these APIs should have the type like T | undefined
(where T
is the entity) rather than just returning T
unconditionally.
Hey, @camchenry. Thank you for yet another suggestion!
Would T | null
work for your use case? It'd be great to align the returned value, and we do use null
for update/delete operations already:
Lines 136 to 140 in f8da857
I have noticed this some day ago and put it in the pr #67. Today i'll rebase the branch
Yeah, T | null
would work for me, and I'd imagine others as well. For pretty much all intents and purposes, I'd treat null
and undefined
interchangeably. For me, the main thing is being able to use the ??
, and ?.
operators to handle nullish values seamlessly, as well as doing a check like:
const entity = db.entity.findFirst(...);
if (!entity) {
throw new Error(); // or return 404
}
// entity is now guaranteed to not be null/undefined
Thinking about it a little more though, this should probably only apply to the findFirst
function, because it returns the entity directly rather than an array of entities. Because findFirst
is analogous to Array.find
and findMany
is analogous to Array.filter
?
Agree on that: let's retain findMany
returning an empty array in the case when no entities matched the query. I find it a more pleasant data type to work with (both results.length
and results.map
are intuitive on empty results).