You can implement your own wrapper function around hasOwnProperty that does type narrowing.
function hasOwnProperty<T, K extends PropertyKey>(
obj: T,
prop: K
): obj is T & Record<K, unknown> {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
I found this solution here:
TypeScript type narrowing not working when looping
Usage:
const obj = {
a: "what",
b: "ever"
} as { a: string }
obj.b // Type error: Property 'b' does not exist on type '{ a: string; }'
if (hasOwnProperty(obj, "b")) {
// obj is no longer { a: string } but is now
// of type { a: string } & Record<"b", unknown>
console.log(obj.b)
}
The limitation with this approach is that you only get a Record back with the single key added that you specified. This might be fine for some needs, but if you need a more general solution then I suggest a library like Zod which can validate a complex object and give you the full type: https://github.com/colinhacks/zod