I keep running into this issue over and over, when adding expando properties onto DOM element or when doing stuff with node.style
like following for example:
/* @flow */
const unsetStyleProperty = (node:HTMLElement, propertyName:string) => {
node.style[propertyName] = ""
}
My guess is that indexable
signature is intentionally omitted so that flow can distinguish if properties accessed are known or not. I also found that usually casting objects with non-indexable signature to Object solves the problem:
/* @flow */
const unsetStyleProperty = (node:HTMLElement, propertyName:string) => {
const style:Object = node.style
style[propertyName] = ""
}
In the light of it:
Object
as illustrated it reasonable solution, or if it's a bug in flow ?Object
is a way to go, I think it would greatly help users of flow if flow could suggest to use such casting in the "Indexable signature not found in" errors.Object
as illustrated above is not a proper solution here, maybe different solution can be made available and also included in the "Indexable signature not found in" error message.I think I might be running into a similar issue
Here's my code:
_.forEach(style, function (prop: string, key: string) {
$node.style[key] = prop
})
Here's the error I get:
lib/popups/pop-around.js:378
378: $node.style[key] = prop
^^^^^^^^^^^^^^^^ assignment of computed property/element. Indexable signature not found in
378: $node.style[key] = prop
^^^^^^^^^^^ CSSStyleDeclaration
Casting to an object works for me as well. I'm not sure what the desired solution is?
Also when I use Symbols:
const text = Symbol('text')
class Message {
[text]: string
constructor(messageText: string) {
this[text] = messageText
}
text(): string {
return this[text]
}
}
lib/test.js:10
10: [text]: string
^ computed property keys not supported
lib/test.js:13
13: this[text] = messageText
^^^^^^^^^^ assignment of computed property/element. Indexable signature not found in
8: class Message {
^^^^^^^ Message
lib/test.js:17
17: return this[text]
^^^^^^^^^^ access of computed property/element. Indexable signature not found in
8: class Message {
^^^^^^^ Message
also like this:
/* @flow */
class Validator {
foo(str: string): boolean {
return true;
}
bar(str: string): boolean {
Validator['foo']
}
}
7: bar(str: string): boolean {
^ boolean. This type is incompatible with an implicitly-returned undefined.
8: Validator['foo'] ^ access of computed property/element. Indexable signature not found in
8: Validator['foo']
^ statics of Validator
Also in React component methods that use refs:
_handleFocusNextField = (ref) => {
this[ref].TextInput.focus();
}
"Access of computed property/element: Indexable signature not found in 'Component'.
Or for that matter, component ref definitions themselves:
const REF_INPUT_PASSWORD = 'REF_INPUT_PASSWORD';
...
<TextInput
...
ref={(c) => { this[REF_INPUT_PASSWORD] = c; }}
...
/>
Has there been any movement on this ?
Here's my solution for refs (see comments for explanation):
export class SomeComponent extends Component {
refs: {
emailInput: number,
firstNameInput: HTMLInputElement,
lastNameInput: HTMLInputElement,
phoneInput: HTMLInputElement,
referralInput: HTMLInputElement,
[propName: string]: HTMLInputElement,
};
componentDidMount() {
setTimeout((() => {
if (this.firstNameInput) {
// If property is accessed directly using dot notation,
// --> it will reference specific prop flow type
this.refs.firstNameInput.focus();
}
}), 1000);
}
focusNextField = (nextField: ?string) => {
if (nextField) {
const nextFieldRef = `${nextField}Input`;
// If computed prop is accessed via bracket syntax,
// --> it will reference index type
this.refs[nextFieldRef].focus();
this.setState({activeField: nextField});
}
// If you want to use bracket notation, but still get specific flow type,
// --> you will need to make assertions
if (nextField) {
const nextFieldRef = `${nextField}Input`;
if (nextFieldRef === 'firstNameInput') {
// The next statement will use the specific,
// --> 'firstNameInput' type rather than the index type
this.refs[nextFieldRef].focus();
this.setState({activeField: nextField});
}
}
};
// Assign refs using modern approach (link posted below),
// --> but put it within sub-property so that you can use
// --> index type in your flow types (above)
render() {
return (
...
<input
type="text"
ref={(input) => { this.refs.textInput = input; }}
/>
...
);
}
}
Assigning refs:
Refs and the DOM
Typing refs:
Adding types for React refs
Let me know if anyone has questions.
Most helpful comment
Has there been any movement on this ?