When someone asks whether a JavaScript object “has” a property, they usually need one of three different answers: an own key, any key on the prototype chain, or a TypeScript narrowing question that still maps to the same runtime checks. Prefer Object.hasOwn for own keys, understand Object.prototype.hasOwnProperty for legacy compatibility (and its shadowing footgun), and use the in operator when inherited properties should count. For how plain objects relate to maps and literals more broadly, see JavaScript dictionary patterns and object literals.
Verified with Node.js v20.18.2: All code samples and commands in this article were executed successfully.
hasOwnProperty for own keys only
obj.hasOwnProperty('key') returns true only when the key exists as an own property of obj. It does not consult inherited enumerable properties on prototypes.
const myHash = { key1: "value1", key2: "value2" };
console.log(myHash.hasOwnProperty("key1"));
console.log(myHash.hasOwnProperty("key3"));true
falseObjects with a null prototype (Object.create(null)) do not inherit hasOwnProperty; call Object.prototype.hasOwnProperty.call(obj, key) or prefer Object.hasOwn below.
Object.hasOwn (modern replacement)
Object.hasOwn(obj, key) is the static ES2022 helper. It behaves like hasOwnProperty for ordinary objects but avoids needing to invoke a method that might be shadowed on the instance.
const myHash = { key1: "value1", key2: "value2" };
console.log(Object.hasOwn(myHash, "key1"));
console.log(Object.hasOwn(myHash, "key3"));true
falsePrototype chain: own versus inherited
hasOwnProperty / Object.hasOwn return false for keys that only exist on a prototype, while the in operator returns true because it checks the whole chain:
const a = { member: true };
const b = Object.create(a);
console.log(a.hasOwnProperty("member"));
console.log(b.hasOwnProperty("member"));
console.log("member" in b);
console.log(Object.hasOwn(b, "member"));true
false
true
falsein versus Object.hasOwn on inherited keys
const parent = { shared: 1 };
const kid = Object.create(parent);
console.log("shared" in kid);
console.log(Object.hasOwn(kid, "shared"));true
falseUse in when you care whether any layer of the chain exposes a property (for example, checking for a DOM API). Use Object.hasOwn when you only want keys declared on the object literal or assigned directly to that instance.
Own property whose value is undefined
Object.hasOwn answers whether the key exists, not whether the value is truthy. An own property may still hold undefined:
const z = { x: undefined };
console.log(Object.hasOwn(z, "x"));
console.log(z.x === undefined);true
trueIf you also need to reject missing keys, combine Object.hasOwn with whatever value check fits your domain.
Looping keys with Object.keys and Object.hasOwn
Object.keys already returns only own enumerable string keys, so the inner guard is redundant for plain objects but documents intent when keys come from elsewhere:
const obj = {
prop1: "value1",
prop2: "value2",
prop3: "value3",
};
const keys = Object.keys(obj);
for (const key of keys) {
if (Object.hasOwn(obj, key)) {
console.log(`obj has a ${key} property`);
}
}obj has a prop1 property
obj has a prop2 property
obj has a prop3 propertyTypeScript: typescript check if object has property
At runtime, use the same Object.hasOwn / in checks as JavaScript. For types, keyof typeof obj lists known keys on a narrow object type, while if ('token' in obj) narrows unions when obj might be one of several shapes. For optional fields, combine runtime Object.hasOwn with your schema validator (for example Zod) if the object is untrusted JSON.
Summary
Javascript check if object has property flows depend on whether you need own keys only or inherited enumerable keys too: Object.hasOwn answers the own-key question, the in operator includes the prototype chain, and Reflect.has mirrors in for dynamic property names. A frequent FAQ is whether obj.key === undefined proves absence—it does not, because keys can exist while holding undefined.
TypeScript readers searching typescript check if object has property should mirror the same runtime checks while using keyof, in, or discriminated unions for static narrowing. When objects come from JSON APIs, pair these tests with schema validation so you never trust shape alone.
