In the issue microsoft/TypeScript#10485, it was suggested for the in
operator to act as a type guard which can be used to filter unions; this was implemented in microsoft/TypeScript#15256 and released with TypeScript 2.7.
This was not done for Object.prototype.hasOwnProperty()
; if you really feel strongly about this, you might want to file a suggestion for it, noting that a similar suggestion (microsoft/TypeScript#18282) was declined because it was asking for the more controversial narrowing of the key and not the object... and some people have wanted both (microsoft/TypeScript#20363). And there's no guarantee the suggestion would be accepted.
Luckily for you, though, you don't have to wait for this to be implemented upstream. Unlike an operator like in
, the hasProperty()
method is just a library signature that can be altered to act as a user-defined type guard function. What's more, you don't even have to touch the standard library definition; you can use declaration merging to augment the Object
interface with your own signature for hasOwnProperty()
:
// declare global { // need this declaration if in a module
interface Object {
hasOwnProperty<K extends PropertyKey>(key: K): this is Record<K, unknown>;
}
// } // need this declaration if in a module
This definition says that when you check obj.hasOwnProperty("someLiteralKey")
, a true
result implies that obj
is assignable to {someLiteralKey: unknown}
, while a false
result does not. This definition might not be perfect and there are probably quite a few edge cases (e.g., what should obj.hasOwnProperty(Math.random()<0.5?"foo":"bar")
imply? what should obj.hasOwnProperty("foo"+"bar")
imply? they will do weird things) but it works for your example:
const totalIn = ("total" in action) ? action.total : defavlt; // okay
const totalOwnProp = (action.hasOwnProperty("total")) ? action.total : defavlt; // okay
Okay, hope that helps; good luck!
Link to code