Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Element implicitly has an 'any' type because index expression is not of type 'number' [7015]

I've taken the code from David Walsh's css animation callback and modified it to TypeScript. However, I'm getting an error and I don't know why:

interface IBrowserPrefix {
  [key: string]: string;
}

// http://davidwalsh.name/css-animation-callback
function whichAnimationEvent() {
  let x: keyof IBrowserPrefix;
  const el = document.createElement('temp');
  const browserPrefix: IBrowserPrefix = {
    animation: 'animationend',
    OAnimation: 'oAnimationEnd',
    MozAnimation: 'animationend',
    WebkitAnimation: 'webkitAnimationEnd',
  };

  for (x in browserPrefix) {
    if (el.style[x] !== undefined) {
    //           ^---- [TS Error]: Element has 'any' type b/c index expression is not of type 'number'
      return browserPrefix[x];
    }
  }
}
like image 536
skube Avatar asked Nov 28 '18 18:11

skube


People also ask

How do you fix element implicitly has an any type because index expression is not of type number?

The error "Element implicitly has 'any' type because index expression is not of type 'number'" occurs when an array is indexed with a value that is not a number. To solve the error, use an object if storing key-value pairs or use a type assertion.

Has an any type because expression of type string can't be used to index type?

The error "Element implicitly has an 'any' type because expression of type 'string' can't be used to index type" occurs when we use a string to index an object with specific keys. To solve the error, type the string as one of the object's keys.


2 Answers

This is happening because you're attempting to index an object with a numeric index signature with string keys.

for x in browserPrefix will give you back a set of keys, which are strings. However for some reason CSSStyleDeclaration has its index type set to number (and not string) - see https://github.com/Microsoft/TypeScript/issues/17827.

You're getting this error because you have --noImplicitAny turned on. A way to get this working (a hacky way) would be to cast the indexer to a string:

  for (x in browserPrefix) {
    if (el.style[x as any] !== undefined) {
      return browserPrefix[x];
    }
  }

The other way would be to modify the typings (try bumping the issue on github).

while we're here, you should mark x with const and if you're going to use for-in on an object you should make sure that the property belongs to the object to avoid pulling in anything that is inherited in the prototype chain:

  for (const x in browserPrefix) {
    if (browserPrefix.hasOwnProperty(x) && el.style[x as any] !== undefined) {
      return browserPrefix[x];
    }
  }

Alternatively, use for-of with Object.keys instead of for-in.

There's no need to define x ahead of time here.

like image 177
Dan Avatar answered Oct 16 '22 20:10

Dan


There are several problems in the code, the first one is that IBrowserPrefix is defined as having a string index and thus keyof IBrowserPrefix; will actually be string. I would remove the interface and just use let x: keyof typeof browserPrefix;

The next problem is the way typescript defined the CSSStyleDeclaration interface. It only include standard properties, not vendor specific ones.

You could a type assertion to tell the compiler you know what you are doing and ignore the error

export function whichAnimationEvent() {

    const el = document.createElement('temp');
    const browserPrefix = {
        animation: 'animationend',
        OAnimation: 'oAnimationEnd',
        MozAnimation: 'animationend',
        WebkitAnimation: 'webkitAnimationEnd',
    };
    let x: keyof typeof browserPrefix;
    for (x in browserPrefix) {
        if (el.style[x as keyof CSSStyleDeclaration] !== undefined) {
            return browserPrefix[x];
        }
    }
}

You could also extend with CSSStyleDeclaration with the vendor specific keys you require.

like image 22
Titian Cernicova-Dragomir Avatar answered Oct 16 '22 22:10

Titian Cernicova-Dragomir