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:
- your TS project uses
emitDecoratorMetadata
- your TS project uses
isolatedModules
- your TS project is set up to modern
moduleResolution
:Bundler
,Node16
orNodeNext
- the imported is referenced in a decorated signature
- the imported type is really just a type or an interface
and lastly:
- 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 import
s 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.