angular/angular · error · Error
Importing a type-only declaration of type ${ts.SyntaxKind[re
Error message
Importing a type-only declaration of type ${ts.SyntaxKind[ref.node.kind]} in a value position is not allowed. What it means
A reference-emit strategy hit a type-only declaration (interface, type alias, etc. — isTypeDeclaration) in a context where a value import is required and AllowTypeImports was not among the import flags, and threw a plain internal Error. Practically: Angular code generation tried to use a type as a runtime value. Types erased at runtime cannot be imported into emitted value positions.
Source
Thrown at packages/compiler-cli/src/ngtsc/imports/src/emitter.ts:349
emit(
ref: Reference,
context: ts.SourceFile,
importFlags: ImportFlags,
): ReferenceEmitResult | null {
if (ref.bestGuessOwningModule === null) {
// There is no module name available for this Reference, meaning it was arrived at via a
// relative path.
return null;
} else if (!isDeclaration(ref.node)) {
// It's not possible to import something which isn't a declaration.
throw new Error(
`Debug assert: unable to import a Reference to non-declaration of type ${
ts.SyntaxKind[ref.node.kind]
}.`,
);
} else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) {
throw new Error(
`Importing a type-only declaration of type ${
ts.SyntaxKind[ref.node.kind]
} in a value position is not allowed.`,
);
}
// Try to find the exported name of the declaration, if one is available.
const {specifier, resolutionContext} = ref.bestGuessOwningModule;
const exports = this.getExportsOfModule(specifier, resolutionContext);
if (exports.module === null) {
return {
kind: ReferenceEmitKind.Failed,
ref,
context,
reason: `The module '${specifier}' could not be found.`,
};
} else if (exports.exportMap === null || !exports.exportMap.has(ref.node)) {
return {View on GitHub (pinned to 51cb07e980)
Solutions
- Replace the type-only symbol with a runtime value: a class or an InjectionToken
- For interface-typed dependencies, add @Inject(MY_TOKEN) with a real InjectionToken<T>
- Keep interfaces and type aliases out of providers arrays, useClass/useExisting/useFactory values, and other value positions in Angular metadata
Example fix
// before
interface Config { url: string }
constructor(private config: Config) {} // type used as DI token
// after
const CONFIG = new InjectionToken<Config>('CONFIG');
constructor(@Inject(CONFIG) private config: Config) {} Defensive patterns
Strategy: validation
Validate before calling
import ts from 'typescript';
// Flag DI constructor params whose type resolves to an interface/type alias (not a class/token)
function isTypeOnlyDeclaration(node: ts.Node): boolean {
return ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node);
} Type guard
function isRuntimeInjectable(symbol: {declarations?: readonly ts.Declaration[]}): boolean {
return (symbol.declarations ?? []).some(
d => ts.isClassDeclaration(d) || ts.isEnumDeclaration(d) || ts.isVariableDeclaration(d),
);
} Prevention
- Use InjectionToken<T> for every interface-typed dependency and @Inject(token) at the injection site
- Never put interfaces or type aliases in providers, useClass, or template value positions
- With verbatimModuleSyntax, audit value imports that only reference types
When it happens
Trigger: Using an interface as a DI token (constructor parameter typed as an interface with no @Inject of a real token); passing a type alias to providers/useClass or another value slot in Angular metadata; templates or generated code referencing type-only symbols as values.
Common situations: Interface-based dependency injection without InjectionToken; config objects typed by interfaces and used as tokens; verbatimModuleSyntax/isolatedModules setups exposing accidental value-position use of types.
Related errors
- VALUE_NOT_LITERAL
- DECORATOR_NOT_CALLED
- DECORATOR_ARG_NOT_LITERAL
- VALUE_NOT_LITERAL
- Unsupported PropertyAccessExpression in TypeTranslatorVisito
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/683b32c4c1ef857f.
Report an issue: GitHub.