52

I'm trying to figure out how to tell react which element is being used as ref i.e. in my case

const circleRef = useRef<AnimatedCircle>(undefined);

AnimatedCircle is an SVG component from a third party library, and defining it this way causes error

enter image description here

Is there some universal way to define which element is ref?

Ilja
  • 44,142
  • 92
  • 275
  • 498
  • 2
    Can you share the definitions of useRef and AnimatedCircle? – Evert Apr 08 '19 at 15:36
  • 1
    Possible duplicate of [Why does 'instanceof' in TypeScript give me the error "'Foo' only refers to a type, but is being used as a value here."?](https://stackoverflow.com/questions/46703364/why-does-instanceof-in-typescript-give-me-the-error-foo-only-refers-to-a-ty) – Heretic Monkey Apr 08 '19 at 15:40

4 Answers4

98

In my case, I renamed the file as .ts instead of .tsx. Renaming it again fixed it.

Ishmeet Singh
  • 1,218
  • 1
  • 8
  • 10
  • 12
    man, all my trouble was this mistake! tanks, you just fixed my situation, 3h into searching all the internet about this. – tmos Feb 03 '20 at 12:36
  • 1
    I was just getting ready to throw my computer out a window — thank you!! The file extension was the last place I was gonna look – Nick Zuber Jul 09 '20 at 18:11
36

AnimatedCircle is a function, not a type. This means it cannot be used in TypeScript in place of a type, like in the generic constraint of useRef. Instead, you need to use the typeof operator to convert to a type:

const circleRef = useRef<typeof AnimatedCircle | null>(null);
Dan
  • 10,282
  • 2
  • 37
  • 64
  • 5
    Constructor functions are typically types too, aren't they? – T.J. Crowder Apr 08 '19 at 15:41
  • 1
    Yes, but since the OP states that `AnimatedCircle` is a component type and they are getting this error I'm willing to bet it's a function and not a class. – Dan Apr 08 '19 at 15:41
  • Unfortunate name for one, if it's not a constructor, as it breaks the basic naming rule of JavaScript/TypeScript. :-) – T.J. Crowder Apr 08 '19 at 15:42
  • 1
    In React, all component types are conventionally TitleCase. Lower case names are used to distinguish between native DOM elements (`div`, `x-your-name-here`, etc) and custom React components (`AnimatedCircle`). While it breaks the convention of *javascript* / *typescript*, it is the convention in React mostly because there's no other non-clumsy way to make React work with custom elements and/or new tags – Dan Apr 08 '19 at 15:44
  • 1
    Oh, I'm v. familiar with that, I'm just used to thinking of them as constructors. But of course, functional components aren't, from TypeScript's type perspective, constructors, and with hooks basically all components become functional ones. Bit of a pain, I expect it'll get addressed. :-) – T.J. Crowder Apr 08 '19 at 15:52
  • 1
    What is the `| null` for? – raarts Apr 24 '20 at 06:41
  • @raarts late reply, sorry! if you used strict null checking in typescript, passing `null` to `useRef` wasn't (isn't?) without explicitly adding it in the type signature and would result in a type error. `useRef(null);` would fail because null is not assignable to `typeof AnimatedCircle` – Dan Apr 27 '21 at 18:49
13

I was getting the same error in

ReactDOM.render(
<App store={store} persistor={persistor} basename={PUBLIC_URL} />,
document.getElementById("root");

And I renamed the file to .tsx and that fixed the problem. The reason is that, when you are using React or ReactDOM, you have to rename file to .tsx instead of ts. For JavaScript, .js works but for TypeScript, .ts don't work.

DevLoverUmar
  • 11,809
  • 11
  • 68
  • 98
  • There is a similar question with the same answer https://stackoverflow.com/questions/58341545/navbar-refers-to-a-value-but-is-being-used-as-a-type-here-when-trying-to-rend – Michael Freidgeim Aug 05 '21 at 14:16
0

For me the problem was I tried to import a type and used it to extend a type:

import type ResultMap form...

tried to do Promise<typeof ResultMap>

But this if not working, because

It’s important to note that classes have a value at runtime and a type at design-time, and the use is context-sensitive. When using import type to import a class, you can’t do things like extend from it. (Source: ts docs)

SAM
  • 742
  • 10
  • 24