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
}

Open in TS playground →

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
}

Open in TS playground →

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`
}

Open in TS playground →

Read more on user-defined type guards in the TS handbook: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates