Typesafe hasOwnProperty in TypeScript
Let’s say you have an object like this:
const something: unknown = {
prop: "value",
};
How do you check that something
indeed has the prop
property? You can surely try something like this:
if (Object.prototype.hasOwnProperty.call(something, "prop")) {
const value = something.prop;
}
This works fine in plain JavaScript, but if you use TypeScript you are going to run into some problems:
if (Object.prototype.hasOwnProperty.call(something, "prop")) {
const value1 = something.prop; // error: Object is of type 'unknown'.
const value2 = (something as any).prop; // ugly and unsafe
}
Fortunately, we can use type guards and generics:
function has<N extends string>(
obj: unknown,
propertyName: N
): obj is {
[K in N]: unknown;
} {
return (
Object(obj) === obj &&
Object.prototype.hasOwnProperty.call(obj, propertyName)
);
}
if (has(something, "prop")) {
typeof something; // => { prop: unknown; }
const value = something.prop; // ok, note that `value` is `unknown` here
}
You may go even further if you want to check the type of prop
:
function hasT<N extends string, T>(
obj: unknown,
propertyName: N,
isT: (value: unknown) => value is T
): obj is {
[K in N]: T;
} {
return has(obj, propertyName) && isT(obj[propertyName]);
}
const isString = (value: unknown): value is string => typeof value === "string";
if (hasT(something, "prop", isString)) {
typeof something; // { prop: string; }
const value = something.prop; // ok, `value` is `string`
}
Read more on user-defined type guards in the TS handbook: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates