2

I am showing this IconButton element conditionally,

{value.content &&
   <IconButton aria-label="copy" onClick={() => copyContent(value.content)}>
     <ContentCopy />
   </IconButton>
}

However I keep getting the typescript warning Argument of type 'string | undefined' is not assignable to parameter of type 'string'. for parameter value.content in copyContent(value.content) . I thought value.content would make the check if its undefined, and if not, not show the element, and no need to worry about the onClick.

Any ideas what I am I missing here? I tried adding value.content && value.content !== undefined, but still get the error.

Thanks.

2
  • Hi, I think the type of the variable value.content be set to string | undefined will fix the issue. Commented Jan 26, 2023 at 3:58
  • Does this fit your need? Please let me know and I can write a more detailed answer. Commented Jan 26, 2023 at 4:16

1 Answer 1

1

You narrowed the type of something in a scope, and then created a function from that to be executed later. And the problem is that, because the function is executed later, you can't be certain that the narrowed you did still applies.

For example:

const value: { content: string | null } = { content: "abc" }

if (value.content) {
  setTimeout(() => {
    console.log(value.content.toUpperCase()) // type error
  }, 1000)
}

value.content = null

This code would crash at runtime. You check value.content, and all seems good. But after you check it the value gets cleared. Then one second later the function runs and value.content.toUpperCase() crashes because value.content is now null.

Maybe that object will change, maybe it won't. But the point is that the Typescript cannot guarantee that it will not change.


You could check it again.

const value: { content: string | null } = { content: "abc" }

if (value.content) {
  setTimeout(() => {
    value.content && console.log(value.content.toUpperCase()) // fine
  }, 1000)
}

value.content = null

Now you've protected yourself against a possible change from some other code.


But what I recommend is to reference content as a local const which can't be reassigned because it's a const.

const value: { content: string | null } = { content: "abc" }

const content = value.content
if (content) {
  setTimeout(() => {
    console.log(content.toUpperCase()) // fine
  }, 1000)
}

value.content = null // does not change the value in `const content` 

And now a change to the value object doesn't matter, because you've pulled the content from it, and if it's changed later then it won't affect this function at all.

See Playground


Or more specific to your case, something like:

function MyComp({ value }: { value: { content: string | null } }) {
  const content = value.content

  return <>{content &&
    <div onClick={() => copyContent(content)}>
      clickMe
    </div>
  }</>
}

See Playground

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for explaining that. Better understood now.

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.