Reputation: 6175
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];
}
}
}
Upvotes: 12
Views: 44558
Reputation: 10538
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.
Upvotes: 13
Reputation: 1148
Try for (x of Object.keys(browserPrefix))
instead of for (x in browserPrefix)
.
It's typically frowned upon to use the in
keyword for a loop, because you may get properties that do not belong to the object.
Upvotes: 2
Reputation: 249506
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.
Upvotes: 3