Skip to content Skip to sidebar Skip to footer

Typescript Can't Assign Value To Object Key With Hasownproperty Type Narrowing

I defined hasOwnProperty with type narrowing: function hasOwnProperty< Obj extends Record, Prop extends PropertyKey, >( obj: Obj, prop: Prop, ): ob

Solution 1:

function hasOwnProperty<
  ObjextendsRecord<string, any>,
  PropextendsPropertyKey,
>(
  obj: Obj,
  prop: Prop,
): obj is Obj & Record<Prop, any> {
  returnObject.prototype.hasOwnProperty.call(obj, prop);
}


function addProp<T>(obj: Record<string, any>, key: string, val: any) {
  if (!hasOwnProperty(obj, key)) {
    obj // <---------------- is infered to never
    obj[key] = val;
  }
}

In your case, obj after condition statement infered to never. Why?

Because type of key is a string and !hasOwnProperty(obj, key) means that obj has no more string keys.

How to fix it ?

You can just add explicit generic for key argument.

function addProp<T, Propextends string>(obj: Record<string, any>, key: Prop, val: any) {
  if (!hasOwnProperty(obj, key)) {
    obj[key] = val;
    return obj
  }
  return obj
}


const x = addProp({}, 'a', 42) // Record<string, any> & Record<"a", any>

Here, in my blog, you can find more issues with mutations in typescript

@captain-yossarian's answer works for functions where I can have a generic for the key. However, in places where I can't use a generic, it still doesn't work (see edit)

This example just can't work:

constobj: Record<string, number> = {};
const key = 'key';
if (!hasOwnProperty(obj, key)) {
  obj[key] = 123;
}

SInce you assume that key property is optional in obj, you should use Partial:

constobj: Partial<Record<PropertyKey, number>> = {};
const key = 'key';
if (!hasOwnProperty(obj, key)) {
  const x = obj
  obj[key] = 123; // ok
}

Post a Comment for "Typescript Can't Assign Value To Object Key With Hasownproperty Type Narrowing"