Flow: Bug: CSSStyleDeclaration bracket notation object accessors throwing type error

Created on 14 Apr 2017  路  8Comments  路  Source: facebook/flow

Here's a simplified version of my code:

// @flow
function a(element: HTMLElement, cssProperty: string, value: string){
    element.style[cssProperty] = value;
}

I get the following error:

  4:     return element.style[cssProperty]
                              ^^^^^^^^^^^ string. This type is incompatible with
  4:     return element.style[cssProperty]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^ number


Found 1 error

I'm new to Flow, but experienced in JavaScript... However I can't seem to figure out what I'm doing wrong. I've tried using the type Element as well as HTMLElement but I keep getting an error.

My actual code (not the simplified version above) is a small function that animates elements using CSS transitions:

//window[prop] is used to prevent Closure's dead code removal or mangler from ruining my code
window["animate"] = function(element: HTMLElement, property: string, value: string, time: number): void{
    if(element.style.transition){
        element.style.transition = property + " " + time+"ms";
    }else{
        element.style.transition = ", " + property + " " + time+"ms";
    }
    element.style[property] = value;
    setTimeout(function () {
        element.style.transition = "";
    }, time)
};
duplicate

Most helpful comment

One of possible solutions is to use setProperty/getPropertyValue instead of bracket notation. Just beware that this requires hyphenated names (background-color not backgroundColor);

All 8 comments

If you look at DOM declaration file (https://github.com/facebook/flow/blob/master/lib/dom.js#L1239), you'll see that the style property on HTMLElement is of type CSSStyleDeclaration, which is also defined (https://github.com/facebook/flow/blob/master/lib/cssom.js#L74).

...based on this, this is what I tried, but doesn't work (removed the value function param for simplicity of example)...

// @flow
function a(element: HTMLElement, prop: $Keys<CSSStyleDeclaration>) {
  console.log(element.style[prop])
}

If you look at the definition for CSSStyleDeclaration (https://github.com/facebook/flow/blob/master/lib/cssom.js#L376), you'll see that it has a defined object accessor that expects number, not $Keys<CSSStyleDeclaration>.

I know I didn't answer your question, but my understanding is that there is currently no safe way to dynamically mutate this value in Flow or Typescript.

You obviously can do this...

// @flow
function updateBackgroundColor(
  element: HTMLElement,
  value: $PropertyType<CSSStyleDeclaration, 'backgroundColor'>,
) {
  element.style.backgroundColor = value;
}

OR

// @flow
function updateBackgroundColor(
  element: HTMLElement,
  value: string,
) {
  element.style.backgroundColor = value;
}

Running into this issue as well. The hacky workaround I'm using is casting the style object to a regular object:

const nodeStyle: Object = domNode.style;

nodeStyle[prop] = 'hi';

I thought for sure I was doing something wrong (new to Flow; this is the first type I'm adding to this project), but apparently not? Would love to see this fixed!

@joshwcomeau Have you tested that? Because JavaScript should create a copy of the style object instead of a reference, making the change useless.

I haven' tried your code yet, but I think it won't do anything.

Sorry, never mind. Your solution works, thanks!

It works, but you're removing type safety. Object is the same as any, just bound to {}.

One of possible solutions is to use setProperty/getPropertyValue instead of bracket notation. Just beware that this requires hyphenated names (background-color not backgroundColor);

Duplicate of #4014

Was this page helpful?
0 / 5 - 0 ratings