3

I'm writing a React app with TypeScript. My component's state looks like this:

type UploadState = {
  ...
  modal: string | null
  ...
}

In my render I have:

render() {
  return <div>{this.renderModal()}</div>
}

somewhere in the code I have:

this.setState({ modal: 'mappingModal' })

and finally renderModel is:

renderModal = () => {
  if (this.state.modal === null) {
    return
  }
  return this[modal as keyof this]() //It doesn't work
}

I EXPECT to have the return value of mappingModal:

mappingModal = () => {
  return <h1>Some text or whatever!</h1>
}

But I get this error because of () in this[modal as keyof this]() :

Cannot invoke an expression whose type lacks a call signature.
Type '{}' has no compatible call signatures.ts(2349)

And if I remove () I get this error in the browser:

Warning: Functions are not valid as a React child.
This may happen if you return a Component instead of <Component /> from render.
Or maybe you meant to call this function rather than return it.

Any solution?

UPDATE (POTENTIAL ANSWER)

It seems if I use this[modal as keyof Upload]() - and Upload is my component name of course - I'll not have any problem. Hopefully it'll not cause any future bug

7
  • this[modal as 'mappingModal']() if 'mappingModal' is a member of this should work. If you have a set of functions on this that have the same signature, typing modal a union of those function names should work .. Commented Feb 19, 2019 at 15:07
  • @TitianCernicova-Dragomir Problem is that I don't know the value of modal in advance. So I can't say something like this[modal as 'mappingModal'](). Your solution works, but I'm looking for something more generic Commented Feb 19, 2019 at 15:13
  • I don't remember why keyof this is troublesome but the idea in whole doesn't look good. Why would a component allow to call any if its methods? It would allow render then, this would hang a browser. In case modal can depend on user input, this is security problem and design problem otherwise. Commented Feb 19, 2019 at 15:14
  • @estus keyof this is not fully known so it acts like a hidden type parameter to the class, derived classes could add to it so this[keyof this] does not get resolved inside the class since you don't really know what the type of this is. But I agree the design has a code smell about it .. Commented Feb 19, 2019 at 15:19
  • @TitianCernicova-Dragomir Notice that it's used inside an arrow, I would expect the compiler to be be pretty much sure what this is. Actually, this likely should be keyof typeof this. Doesn't work this way. Could be a limitation or a bug. Commented Feb 19, 2019 at 15:34

1 Answer 1

1

It seems if I use this[modal as keyof Upload]() - and Upload is my component name of course - I'll not have any problem. Like this:

class Upload extends React.Component<UploadProps, UploadState> {
  ...
  renderModal = () => {
    if (this.state.modal === null) {
      return
    }
    return this[modal as keyof Upload]()
  }
  ...
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.