I'm writing a type guard for an interface, and I'm noticing that I cannot narrow object with in or Object.hasOwnProperty.call or arg.hasOwnProperty. Like this:
interface Test {
quest: string;
}
function isTest(arg: unknown): arg is Test {
// this successfully narrows arg to "object"
if (typeof(arg) !== "object" || arg === null) {
return false;
}
if (!Object.hasOwnProperty.call(arg, "quest")) {
return false;
}
// at this point, I still cannot access arg.quest, because
// "Property 'quest' does not exist on type 'object'". The same thing happens
// if I invert the check and try to access it inside the conditional.
if (!arg.hasOwnProperty("quest")) {
return false;
}
// same problem, cannot access arg.quest because arg is still just "object"
if (!("quest" in arg)) {
return false;
}
// still the same problem.
return true;
}
Because of this, I'm having to do a lot of type casting, which is annoying because the actual interface I want to check has many properties, not all of which are basic primitives. So basically, for each property I have to make something that looks like this:
function isTest(arg: unknown): arg is Test {
if (typeof(arg) !== "object" || arg === null) {
return false;
}
if (!Object.hasOwnProperty.call(arg, "quest")) {
return false;
}
if (typeof((arg as {quest: unknown}).quest) !== "string") {
return false;
}
return true;
}
... and generally, I feel like if I have to use as I've done something wrong. So how do I narrow object to an interface without writing a separate type guard for each property of the interface?
As to why I need such robust guards, it's because this is going in a server and I'm checking payloads sent to its API after being JSON.parsed so that I can do complex operations with them without worrying about finding out halfway through that the data is poorly structured.