Ivosein
Ivosein

Reputation: 63

Typescript index signature failure Angular objects

I have the following angular typescript code.

In the function 'blendBinA' keep getting the error:

"Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ObjA'.ts(7053)"

How to fix ?

interface ObjA {
    propA: string;
    propB: number;
    propC: string[];
}

public objA: ObjA = { propA: 'Henk', propB: 23, propC: ['singel 23'] };
public objB: any = { propX: '6445 GB', propA: 'henk' };

blendBinA() {
    for (const k in this.objB) {
        if (this.objA.hasOwnProperty(k)) {
            this.objA[k] = this.objB[k];
        }
    }
}

Upvotes: 1

Views: 174

Answers (1)

This is because this.objA.hasOwnProperty(k) does not acts like a type guard.

You need to define your own custom typeguard:

const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
  : obj is Obj & Record<Prop, unknown> =>
  Object.prototype.hasOwnProperty.call(obj, prop);

and then try:

interface ObjA {
  propA: string;
  propB: number;
  propC: string[];
}


const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
  : obj is Obj & Record<Prop, unknown> =>
  Object.prototype.hasOwnProperty.call(obj, prop);

class Foo {

  public objA: ObjA = { propA: 'Henk', propB: 23, propC: ['singel 23'] };
  public objB: any = { propX: '6445 GB', propA: 'henk' };

  blendBinA() {
    for (const k in this.objB) {
      if (hasProperty(this.objA, k)) {
        this.objA[k] = this.objB[k];
      }
    }
  }
}

Playground

If it possible, try to type objB

P.S. It is possible to force hasOwnProperty to behave like typeguard:

See this example:

type Tag = { [prop: `tag${number}`]: never }

interface Object {
  hasOwnProperty(v: PropertyKey): boolean & Tag
}

interface CallableFunction extends Function {
  call<
    T,
    Prop extends string,
    R extends boolean & Tag
  >(this: (this: T, property: Prop) => R, thisArg: T, property: Prop): thisArg is T & Record<Prop, string>;
}

declare const obj: { name?: string, surname?: number }

if (Object.prototype.hasOwnProperty.call(obj, 'name')) {
  const test = obj.name // string
}

if (Object.prototype.propertyIsEnumerable.call(obj, 'name')) {
  const test = obj.name // string | undefined
}

Here you can find related question and answer with more explanation.

Here you will find my article with some examples

Upvotes: 1

Related Questions