A type referenced in a decorated signature must be imported with ‘import type’ or a namespace import when ‘isolatedModules’ and ‘emitDecoratorMetadata’ are enabled.

What does it mean, when can it happen and what should you do about it?

When

The following conditions must be met in order to trigger this error:

  1. your TS project uses emitDecoratorMetadata
  2. your TS project uses isolatedModules
  3. your TS project is set up to modern moduleResolution: Bundler, Node16 or NodeNext
  4. the imported is referenced in a decorated signature
  5. the imported type is really just a type or an interface

and lastly:

  1. the type is imported without the type specifier: import { Foobar } from 'foobar'

About the conditions

1. emitDecoratorMetadata

You need to have this enabled to make sure that the experimental decorators get proper metadata using the Metadata Reflection API (reflect-metadata)

2. isolatedModules

With this option enabled, TypeScript helps you write code that will be valid when transpiled with tools other than tsc. One of the characteristics of this mode is that each file needs to be correctly transpilable (is that a word?) without the transpiler having to look at other files.

3. moduleResolution

Long story short, the old (<4.7?) default for CJS projects node (now named Node10) is pretty outdated and does not support most of the things you’d like it to support. You should either use Node16 as the default for Node apps (no matter if they are ESM or CJS), or Bundler if you’re using something else than tsc to transpile the app. NodeNext is currently equivalent to Node16, but it will change with future releases, the same way as ESNext target moves forward with time.

In our case Node10 does not trigger the 1272 error, which is bad, because the compiler error prevents you from (spoiler alert) writing code that can crash in runtime.

4. The type is referenced in a decorated signature

When you use the experimental decorators, they have access to the type of the decorated property/class. It’s available with Reflect metadata under design:paramtypes key.

The error is about importing types of these decorated properties/classes.

5. The imported type is really just a type

It is possible to “import type” something like a class or a variable – you explicitly tell bundlers that you don’t need to import the actual object in runtime, you are just using its type for typechecking.

But there are also actual types and interfaces, not available in runtime, that you can either import or import type. I am not sure how bundlers realize that import of an interface is to be deleted, but I guess it looks at the usages inside the transpiled file. Or maybe it does not delete it, I don’t know.

The error is about importing the types/interfaces that are not resolvable to anything in runtime.

What’s wrong with the conditions

The bundlers (2) know that they should remove import type statements when emitting code. Let’s skip the part where the bundlers may or may not remove import statements of types/interfaces (because I don’t yet know how it works) and assume the bundlers know that they should not remove the imports of types referenced in decorated signatures (4), because they need to import the actual objects, to emit additional metadata code (1).

But if the type is just a type (5), you won’t get any runtime metadata, and it is possible that the bundler will create code that crashes in runtime due to the fact that the metadata code will try to import something which does not exist in runtime.

That is why you need to tell the bundler that it’s just a type with import type. Only then you are sure the bundler will remove the whole statement and skip collecting metadata for the decorators during transpilation, by simply not producing any require/import in the output files.

And the error is not reported for the deprecated Node10 (a.k.a node) moduleResolution, which is another reason to migrate to Node16/Bundler (3).

And that’s what’s the error is about:

A type referenced in a decorated signature must be imported with ‘import type’ or a namespace import when ‘isolatedModules’ and ‘emitDecoratorMetadata’ are enabled.